smtp-receiver

A small persistent SMTP listener that accepts incoming mail and writes each complete message as a file in an inbox directory.

This first version is intentionally permissive: it accepts any sender and recipient, does not perform spam filtering, and only applies coarse rate limits to avoid overload.

Behavior

  • Listens on SMTP_LISTEN_ADDR (default 0.0.0.0:2525).
  • Supports basic SMTP commands: HELO/EHLO, MAIL FROM, RCPT TO, DATA, RSET, NOOP, and QUIT.
  • Applies a global messages-per-minute limit and a per-envelope-sender messages-per-minute limit.
  • Writes message data to a temporary directory first, then atomically renames the complete file into the inbox.
  • Also writes a cleaned copy into SMTP_CLEANED_INBOX_DIR for LLM ingestion.
  • Keeps temporary files outside both inboxes by default, so future rsync jobs can read inboxes without seeing partial messages.
  • Prepends envelope metadata headers before the received DATA payload.
  • Message filenames use [YYYY]-[MM]-[DD]-[base64_url encoded sha1 content hash].eml, based on the full original stored message content.
  • Cleaned copies strip X-*, ARC-*, and DKIM* headers except X-Received and X-SMTP*, keep plain-text bodies, drop HTML alternatives, and keep attachments with minimal MIME headers.

Configuration

Environment variables:

Variable Default Description
SMTP_LISTEN_ADDR 0.0.0.0:2525 TCP listen address. Use 0.0.0.0:25 in a privileged/container deployment.
SMTP_INBOX_DIR inbox Directory where complete .eml files are delivered.
SMTP_CLEANED_INBOX_DIR sibling inbox-cleaned Directory where stripped LLM-ingestion .eml files are delivered.
SMTP_TEMP_DIR sibling .smtp-receiver-tmp Temporary write directory used before atomic rename into the inboxes.
SMTP_MAX_MESSAGE_BYTES 26214400 Maximum SMTP DATA size.
SMTP_GLOBAL_RATE_PER_MINUTE 600 Global accepted MAIL FROM commands per rolling minute. Set 0 to disable.
SMTP_SENDER_RATE_PER_MINUTE 60 Per-sender accepted MAIL FROM commands per rolling minute. Set 0 to disable.

Local development

cargo fmt
cargo test
SMTP_LISTEN_ADDR=127.0.0.1:2525 SMTP_INBOX_DIR=tmp/inbox cargo run

Example manual smoke test:

nc 127.0.0.1 2525

Then type:

EHLO local
MAIL FROM:<sender@example.test>
RCPT TO:<inbox@example.test>
DATA
Subject: hello

body
.
QUIT

Deployment note

The service currently runs in CT 120 on udo-pve2.

S
Description
No description provided
Readme
362 KiB
0 Stars 1 Watchers 0 Forks
Languages
Rust 100%