Overview
| Comment: | clean Cargo, rewrite telegram support |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
d711370ce3b8d2346b25a9a46f9b5d06 |
| User & Date: | arcade on 2026-09-11 19:42:09.499 |
| Other Links: | manifest | tags |
Context
|
2026-09-12
| ||
| 20:00 | clarify docs, change file check check-in: e678fcdc39 user: arcade tags: trunk | |
|
2026-09-11
| ||
| 19:42 | clean Cargo, rewrite telegram support check-in: d711370ce3 user: arcade tags: trunk | |
|
2026-09-10
| ||
| 07:07 | bump check-in: cb1fdeff6f user: arcade tags: trunk | |
Changes
Modified Cargo.lock
from [7ce5ee1c1b]
to [4889e5fadd].
| ︙ | ︙ | |||
1781 1782 1783 1784 1785 1786 1787 | "async-process", "blocking", "futures-lite", ] [[package]] name = "smtp2tg" | | | 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 | "async-process", "blocking", "futures-lite", ] [[package]] name = "smtp2tg" version = "0.6.8" dependencies = [ "async-compat", "clap", "config", "hostname", "html-escape", "mail-parser", |
| ︙ | ︙ |
Modified Cargo.toml
from [2e2ef2ad27]
to [009bbb470f].
| ︙ | ︙ | |||
15 16 17 18 19 20 21 | mail-parser = "0.11" mailin-embedded = "0.8" regex = "1.11.1" smol = "2.0.2" stacked_errors = "0.8" tgbot = "0.48" | < < < < | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | mail-parser = "0.11" mailin-embedded = "0.8" regex = "1.11.1" smol = "2.0.2" stacked_errors = "0.8" tgbot = "0.48" # All tests are moved to tests/ [lib] test = false [[bin]] test = false name = "smtp2tg" |
Modified src/mail.rs
from [1c18fc67bc]
to [6cd87852dc].
| ︙ | ︙ | |||
55 56 57 58 59 60 61 |
#[derive(Clone, Debug)]
pub struct MailServer {
data: Vec<u8>,
headers: Option<SomeHeaders>,
tg: Arc<TelegramTransport>,
fields: HashSet<String>,
address: Regex,
| < | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
#[derive(Clone, Debug)]
pub struct MailServer {
data: Vec<u8>,
headers: Option<SomeHeaders>,
tg: Arc<TelegramTransport>,
fields: HashSet<String>,
address: Regex,
}
impl MailServer {
/// Initializes the mail server: sets up the Telegram API client and
/// validates all required configuration values.
///
/// # Arguments
|
| ︙ | ︙ | |||
110 111 112 113 114 115 116 |
Ok(MailServer {
data: vec!(),
headers: None,
tg,
fields,
address,
| < | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
Ok(MailServer {
data: vec!(),
headers: None,
tg,
fields,
address,
})
}
/// Retrieves the Telegram chat ID for a given email address, checks that
/// used domain is allowed.
///
/// # Arguments
|
| ︙ | ︙ |
Modified src/telegram.rs
from [683b75dd50]
to [4d6fd6327a].
| ︙ | ︙ | |||
14 15 16 17 18 19 20 |
bail,
Result,
StackableErr,
};
use tgbot::{
api::Client,
types::{
| < < < | < < < < < < < | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
bail,
Result,
StackableErr,
};
use tgbot::{
api::Client,
types::{
ChatPeerId, InputFile, InputFileReader, InputMediaDocument, InputText, MediaGroup, MediaGroupItem, Message, ParseMode::Html, SendDocument, SendMediaGroup, SendMessage
},
};
#[derive(Debug)]
pub struct TelegramTransport {
tg: Client,
recipients: HashMap<String, ChatPeerId>,
|
| ︙ | ︙ | |||
77 78 79 80 81 82 83 |
///
/// # Returns
/// * `Result<Message>` - Telegram API response.
///
/// # Errors
/// Returns an error if `msg` contains a closing Telegram tag or sending fails.
pub async fn debug (&self, msg: &str) -> Result<Message> {
| | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
///
/// # Returns
/// * `Result<Message>` - Telegram API response.
///
/// # Errors
/// Returns an error if `msg` contains a closing Telegram tag or sending fails.
pub async fn debug (&self, msg: &str) -> Result<Message> {
self.send(&self.default, &format!("<pre>{}</pre>", validate(msg).stack()?)).await
}
/// Retrieves a chat ID by name.
///
/// # Arguments
/// * `name` - Name or email to look up.
///
|
| ︙ | ︙ | |||
103 104 105 106 107 108 109 | /// /// # Arguments /// * `to` - Target chat ID. /// * `msg` - Message text (supports HTML formatting). /// /// # Returns /// * `Result<Message>` - Telegram API response. | | < | < | < < < < < < < | | | < < > > > > > > | | | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
///
/// # Arguments
/// * `to` - Target chat ID.
/// * `msg` - Message text (supports HTML formatting).
///
/// # Returns
/// * `Result<Message>` - Telegram API response.
pub async fn send (&self, to: &ChatPeerId, msg: &str) -> Result<Message> {
self.tg.execute(
SendMessage::new(*to, InputText::from(msg).with_format(Html))
).await.stack()
}
/// Sends a message with attachments to a specified chat.
///
/// # Arguments
/// * `to` - Target chat ID.
/// * `media` - List of attachments, non-empty.
/// * `msg` - Message text (supports HTML formatting).
///
/// # Returns
/// * `Result<()>` - Success or error.
pub async fn sendgroup (&self, to: &ChatPeerId, media: Vec<Attachment>, msg: &str) -> Result<()> {
if media.len() > 1 {
let mut attach = vec![];
let mut pos = media.len();
for file in media {
let mut doc = InputMediaDocument::from(
InputFile::from(
InputFileReader::from(file.data)
.with_file_name(file.name)
)
);
if pos == 1 {
doc = doc.with_caption(InputText::from(msg)
.with_format(Html));
}
pos -= 1;
attach.push(MediaGroupItem::from(doc));
}
self.tg.execute(SendMediaGroup::new(*to, MediaGroup::new(attach).stack()?)).await.stack()?;
} else {
if media.is_empty() {
bail!("At least one attachment is required.");
}
self.tg.execute(
SendDocument::new(
*to,
InputFileReader::from(media[0].data.clone())
.with_file_name(media[0].name.clone())
).with_caption(InputText::from(msg)
.with_format(Html))
).await.stack()?;
}
Ok(())
}
}
|