Skip to main content

A drop-in sendmail replacement that forwards system emails to Telegram.

Project description

Telegram Sendmail Bridge Telegram Sendmail Bridge

A drop-in sendmail replacement that forwards system emails to Telegram.

License: MIT Python: 3.10+ CI


Overview

telegram-sendmail intercepts emails that system daemons — cron, logwatch, fail2ban, and others — send through the standard sendmail interface and forwards them to a Telegram chat as formatted messages. It operates as a true drop-in replacement: any application that calls /usr/sbin/sendmail will work without modification.

Two modes of operation are supported:

  • Pipe mode (default): reads a raw RFC 2822 email from stdin, the standard interface used by cron and the majority of Unix system daemons.
  • SMTP server mode (-bs): runs a minimal SMTP state machine on stdin/stdout for applications that speak SMTP directly to the sendmail binary.

Features

  • Parses both plain-text and HTML MIME emails
  • Sanitises HTML through a two-pass pipeline: dangerous tags (<script>, <style>, <iframe>, etc.) and their entire subtrees are stripped before conversion; safe content is then mapped to Telegram's supported markup subset
  • Detects and reports MIME attachments without forwarding binary content or disclosing filenames
  • Smart message truncation at word boundaries with a configurable length limit
  • Archives every raw email to a local spool file before attempting Telegram delivery, ensuring no message is lost if the network is unavailable
  • Structured logging to syslog (LOG_MAIL facility) with an optional --console mode for interactive debugging
  • Full sendmail-compatible flag support: -f, -r, -s, -bs, -t, -i, -oi, plus silent acceptance of positional recipient arguments
  • Configurable HTTP retry strategy with exponential backoff for resilience against transient Telegram API failures
  • EX_TEMPFAIL (exit code 75) signalling on HTTP 429/5xx so MTA-aware daemons re-queue and retry automatically
  • Distributed as a standalone binary with no runtime dependencies via the release pipeline

Requirements

The standalone binary has no runtime requirements. Source-based installation requires:

Installation

Step 1 — Install the binary

Option A — Pre-built standalone binary (recommended):

Standalone binaries for x86_64 and aarch64 are attached to every GitHub Release. They have no runtime dependencies — Python is not required on the target host.

Both binaries are built on Ubuntu 22.04 and link against glibc 2.35. They are forward-compatible with any Linux distribution shipping glibc 2.35 or newer (Debian 12, Ubuntu 22.04+, RHEL 9+, Fedora 36+). Source-based installation is required on older distributions.

# Detect the host architecture (x86_64 or aarch64)
ARCH=$(uname -m)

# Download the binary and its SHA-256 checksum
curl -LO "https://github.com/theodiv/telegram-sendmail/releases/latest/download/telegram-sendmail-linux-${ARCH}"
curl -LO "https://github.com/theodiv/telegram-sendmail/releases/latest/download/telegram-sendmail-linux-${ARCH}.sha256"

# Verify integrity before installing
sha256sum --check "telegram-sendmail-linux-${ARCH}.sha256"

# Install to a system PATH location and verify
sudo install -m 0755 "telegram-sendmail-linux-${ARCH}" /usr/local/bin/telegram-sendmail
telegram-sendmail --version

Option B — Install from PyPI

Requires Python 3.10 or later on the target host.

# Recommended: install with pipx (automatic isolation)
pipx install telegram-sendmail

# Alternative: install into the system Python
pip install telegram-sendmail

# Verify the installation
telegram-sendmail --version

Step 2 — Create a configuration file

Create /etc/telegram-sendmail.ini (system-wide) or ~/.telegram-sendmail.ini (per-user). The user config takes priority when both files exist. A fully-commented template covering every available key is included in the repository as telegram-sendmail.ini.example.

# Source installs: the example file is available in the repository clone
sudo cp telegram-sendmail.ini.example /etc/telegram-sendmail.ini

# Binary installs: download the template from the repository
sudo curl -L https://raw.githubusercontent.com/theodiv/telegram-sendmail/main/telegram-sendmail.ini.example -o \
    /etc/telegram-sendmail.ini

sudo chmod 600 /etc/telegram-sendmail.ini
sudo $EDITOR /etc/telegram-sendmail.ini

Security: The config file contains the bot token. Permissions must be 0600. A WARNING is emitted to syslog if the file is group- or world-readable, but execution is not blocked — the operator is expected to correct the permissions.

Step 3 — Register as the system sendmail

telegram-sendmail intentionally does not register itself as /usr/sbin/sendmail during installation to avoid silently overwriting an existing MTA.

Option A — Simple symlink (no existing MTA):

TGSM_BIN=$(which telegram-sendmail)
sudo ln -sf "$TGSM_BIN" /usr/sbin/sendmail
sudo ln -sf "$TGSM_BIN" /usr/bin/sendmail

Option B — update-alternatives (Debian/Ubuntu, existing MTA present):

TGSM_BIN=$(which telegram-sendmail)

sudo update-alternatives --install \
    /usr/sbin/sendmail sendmail "$TGSM_BIN" 50

# Interactively select the active alternative
sudo update-alternatives --config sendmail

Set the priority value (50 above) lower than the existing MTA's registered priority if telegram-sendmail should serve as a fallback, or higher to make it the active default.

To revert to the original MTA:

sudo update-alternatives --remove sendmail "$TGSM_BIN"

Configuration

All configuration lives in a single INI file with two required keys and a number of optional tuning parameters.

[telegram]
; Required — Telegram Bot API token from @BotFather
token = 123456789:AAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

; Required — destination chat ID (personal, group, or channel)
chat_id = -1001234567890

[options]
; All keys below are optional. Out-of-range or malformed values fall
; back to their documented defaults with a WARNING logged to syslog.

; Spool directory. Effective path: <spool_dir>/<username>
; Default: /var/mail
spool_dir = /var/mail

; Maximum body length forwarded to Telegram (100–4096). Default: 3800
message_max_length = 3800

; SMTP session idle timeout in seconds (5–300). Default: 30
smtp_timeout = 30

; Telegram API request timeout in seconds (5–60). Default: 10
telegram_timeout = 10

; Retry attempts on 429/5xx responses (0–10). Default: 3
max_retries = 3

; Exponential backoff multiplier (0.0–10.0). Default: 0.5
; Effective pause before attempt n: backoff_factor × 2^(n-1) seconds
backoff_factor = 0.5

; Suppress notification sound and banner. Default: false
disable_notification = false

The complete annotated template is provided in telegram-sendmail.ini.example.

Mail Spool — Reliability Design

Every email is archived to a local spool file before any attempt is made to contact the Telegram API. This guarantees that the original message is preserved on disk regardless of network availability or downstream parsing failures.

The spool file path is <spool_dir>/<username> (e.g. /var/mail/root). If the configured directory is not writable at startup — common in container environments — the daemon falls back to /tmp/.telegram-sendmail-spool/<username> and emits a WARNING to syslog. This hidden subdirectory is created automatically with 0700 DAC permissions to prevent cross-user data exposure in the world-writable /tmp filesystem.

A SpoolError is explicitly non-fatal: if the spool write fails, the message is still forwarded to Telegram and the failure is logged at WARNING level.

File permissions on the spool file are enforced to 0600 via os.fchmod against the open file descriptor on every write. This eliminates the TOCTOU race condition that would exist between file creation and a subsequent os.chmod call.

Usage

In normal operation the tool is invoked by system daemons through the sendmail interface. The examples below are useful for integration testing and interactive debugging.

# Basic pipe mode
echo -e "Subject: Test\n\nThis is a test message." | telegram-sendmail

# Explicit sender and subject override
echo "Disk usage critical." | telegram-sendmail -f root@hostname -s "Disk Alert"

# As called by cron (positional recipient is silently discarded)
echo "Cron job failed." | telegram-sendmail -oi -t root@localhost

# SMTP server mode
telegram-sendmail -bs

# Interactive debugging with console logging
echo "Hello" | telegram-sendmail --console --debug

Exit Codes

Code Name Meaning
0 EX_OK Message delivered successfully to Telegram.
1 EX_ERROR Operational failure: parse error, API error, or unexpected exception.
75 EX_TEMPFAIL Transient failure (HTTP 429/5xx). Daemons will re-queue and retry.
78 EX_CONFIG Configuration error: file missing, unreadable, or missing required key.

Exit code 75 is the standard EX_TEMPFAIL value from sysexits.h. POSIX-aware daemons interpret this as a signal to retry later rather than treating the message as permanently undeliverable.

Troubleshooting

Checking logs

All output goes to syslog under the LOG_MAIL facility:

# Live log stream
journalctl -t telegram-sendmail -f

# Recent entries
journalctl -t telegram-sendmail --since "1 hour ago"

On systems without journald, check /var/log/mail.log or /var/log/syslog.

Common issues

No messages arriving in Telegram — Verify token and chat_id, confirm the bot has been started (/start in the Telegram app), and check that outbound HTTPS to api.telegram.org is permitted by the host firewall. Running with --console --debug reveals the full API error payload.

Permission denied on config file — The file must be owned by the process user with 0600 permissions:

sudo chmod 600 /etc/telegram-sendmail.ini
sudo chown root:root /etc/telegram-sendmail.ini

Cron emails not forwarded — Verify the symlink resolves correctly:

ls -la /usr/sbin/sendmail
/usr/sbin/sendmail --version

Spool directory warning in logs — Either make the spool directory writable by the process user, or set spool_dir in [options] to a path that is.

Binary fails to start with "GLIBC not found" error — The pre-built binary requires glibc 2.35 or newer. Install from source on older distributions.

Contributing

Contributions are welcome. Please read CONTRIBUTING.md before opening a pull request.

Changelog

See CHANGELOG.md for a full history of notable changes.

Security

Security vulnerabilities must not be disclosed via public issues. See SECURITY.md for the responsible disclosure process.


Distributed under the MIT License  •  Made with ♥ for the Linux sysadmin community

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

telegram_sendmail-1.0.0.tar.gz (128.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

telegram_sendmail-1.0.0-py3-none-any.whl (34.5 kB view details)

Uploaded Python 3

File details

Details for the file telegram_sendmail-1.0.0.tar.gz.

File metadata

  • Download URL: telegram_sendmail-1.0.0.tar.gz
  • Upload date:
  • Size: 128.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for telegram_sendmail-1.0.0.tar.gz
Algorithm Hash digest
SHA256 602d852d7edf49526d726a357fb725536d1d9e122dc0227c69aeb7a0db280b79
MD5 a448e812caeafd5cc364a0d0d46d619f
BLAKE2b-256 34be9f27f5fc6ad3eec36d0fe3f8fe6ab374b1188b0d9002b549ca4b1ef840ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for telegram_sendmail-1.0.0.tar.gz:

Publisher: pypi.yml on theodiv/telegram-sendmail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file telegram_sendmail-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for telegram_sendmail-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fc6dfd57a3ecc64167ec03a5f7def0dc3f3308555cfa6ac2299ef940e3374be1
MD5 da1d375563a51a903e9b9dd97e51dde9
BLAKE2b-256 003218a3ef767a77725f1e96b09f88945733cbd5ca33560104f19d0644f02c73

See more details on using hashes here.

Provenance

The following attestation bundles were made for telegram_sendmail-1.0.0-py3-none-any.whl:

Publisher: pypi.yml on theodiv/telegram-sendmail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page