Overview
| Comment: | doc corrections/optimizations |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
1723b63d6980199b9bd26a6af71be204 |
| User & Date: | arcade on 2026-08-01 13:46:06.271 |
| Other Links: | manifest | tags |
Context
|
2026-08-01
| ||
| 15:30 | fix regexp, get rid of relaying variants as they are actually noop after move to mailin check-in: 158c9cffc6 user: arcade tags: trunk | |
| 13:46 | doc corrections/optimizations check-in: 1723b63d69 user: arcade tags: trunk | |
| 11:30 | remove serde dep for mail-parser check-in: b9bf773618 user: arcade tags: trunk | |
Changes
Modified README.md
from [438799e731]
to [3b91b4e83f].
| ︙ | |||
17 18 19 20 21 22 23 | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | - + | 1. Create `smtp2tg.toml` (see `smtp2tg.toml.example` for reference). 2. Get a Telegram Bot Token from [@BotFather](https://t.me/BotFather). 3. Get your chat ID (use [@getidsbot](https://t.me/getidsbot) or debug mode in Telegram client). ### Example configuration ```toml |
| ︙ | |||
54 55 56 57 58 59 60 61 62 63 64 65 66 67 | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | + | ### Run ```bash ./smtp2tg -c /path/to/smtp2tg.toml ``` ### CLI arguments | Argument | Description | Example | |---------------|---------------------------|-----------------------| | `-h`, `--help` | Show help | `smtp2tg --help` | | `-c`, `--config` | Path to config file | `smtp2tg -c config.toml` | --- |
| ︙ | |||
84 85 86 87 88 89 90 | 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | - + - + | ## How it works 1. A client (e.g., Postfix) sends an email to `listen_on` (e.g., `127.0.0.1:1025`). 2. smtp2tg parses the email and converts it to a Telegram message. 3. The message is sent to the specified chat (or `default` if address is unknown). ### Example: Email → Telegram **Incoming email:** |
Modified src/mail.rs
from [48b0e1b904]
to [3f2e34fec5].
| ︙ | |||
58 59 60 61 62 63 64 | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | - + + - - + + - + - + |
relay: bool,
tg: Arc<TelegramTransport>,
fields: HashSet<String>,
address: Regex,
}
impl MailServer {
|
| ︙ | |||
119 120 121 122 123 124 125 | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | - + - + - - - | }) } /// Retrieves the Telegram chat ID for a given email address, checks that /// used domain is allowed. /// /// # Arguments |
| ︙ | |||
290 291 292 293 294 295 296 | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | - + - - - - - - - + - - - |
/// Just deny plain auth
fn auth_plain (&mut self, _authorization_id: &str, _authentication_id: &str, _password: &str) -> Response {
INVALID_CREDENTIALS
}
/// Verify whether address is deliverable
fn rcpt (&mut self, to: &str) -> Response {
|
| ︙ |
Modified src/telegram.rs
from [5758349194]
to [4f9a819f27].
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | + |
//! Telegram API integration for sending messages and attachments.
use crate::utils::{
Attachment,
validate,
};
use std::{
collections::HashMap,
fmt::Debug,
};
use stacked_errors::{
bail,
Result,
StackableErr,
};
use tgbot::{
api::Client,
types::{
ChatPeerId,
|
| ︙ | |||
43 44 45 46 47 48 49 | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | + - + | /// /// # Arguments /// * `api_key` - Telegram Bot API token. /// * `recipients` - Mapping of email addresses to Telegram chat IDs. /// * `settings` - Additional configuration (API gateway, default chat). /// /// # Errors /// Returns an error if configuration values cannot be read or if Telegram |
| ︙ | |||
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | + + + + + + |
/// Sends a debug message to the default chat.
///
/// # Arguments
/// * `msg` - Message text to send.
///
/// # 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.
///
/// # Returns
/// * `Result<&ChatPeerId>` - Chat ID if found.
///
/// # Errors
/// Returns an error if `name` is not configured.
pub fn get (&self, name: &str) -> Result<&ChatPeerId> {
self.recipients.get(name)
.with_context(|| format!("Recipient \"{name}\" not found in configuration"))
}
/// Sends a text message to a specified chat.
///
|
| ︙ | |||
107 108 109 110 111 112 113 | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | - + | ).await.stack() } /// Sends a message with attachments to a specified chat. /// /// # Arguments /// * `to` - Target chat ID. |
| ︙ | |||
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | + + + |
),
caption
)
);
}
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(msg)
.with_caption_parse_mode(Html)
).await.stack()?;
}
Ok(())
}
}
|