SMTP Session & Dispatch
Relevant source files
The following files were used as context for generating this wiki page:
SMTP Session & Dispatch governs the lifecycle of email submission in Mailiner. It encompasses the validation and serialization of drafts into MIME messages, the management of an asynchronous outbox for reliable delivery, and the orchestration of secure SMTP connections to remote servers.
The system is designed to handle the limitations of browser environments by using WebSocket-to-TCP proxies, ensuring that even when running in WASM, the client can perform standard RFC 5321 and RFC 5322 operations. It prioritizes security by performing encryption (TLS) on the browser side before traffic reaches the proxy.
Message Preparation and Export
Before dispatch, a DraftDocument must be converted into a PreparedMessage. This process validates the draft against hard limits (caps) and generates the necessary SMTP envelope and RFC 822 compliant byte stream.
Draft Validation and Serialization
The prepare_submit function orchestrates the transformation of a draft. It ensures the draft has at least one recipient and that all attachments are fully loaded.
- Envelope Generation: Extracts unique email addresses for
MAIL FROMandRCPT TOcommands. - Header Construction: Generates standard headers such as
From,To,Subject,Date, and a uniqueMessage-ID. - MIME Tree Building: Constructs a multipart tree based on the presence of plain text, HTML, inline images, and attachments.
Sources: crates/mailiner-composer/src/export.rs:43-100, crates/mailiner-composer/src/model/draft.rs:245-340
MIME Structure Logic
The following diagram illustrates how the MIME tree is nested depending on the draft content:
The MIME writer ensures all parts are transfer-encoded (Base64 or Quoted-Printable) and folded to 78-octet lines as per RFC 5322.
Sources: crates/mailiner-composer/src/export.rs:200-248, crates/mailiner-mime/src/writer/mod.rs:203-240
The Outbox System
Mailiner uses an asynchronous outbox to manage messages queued for sending. This ensures that network interruptions do not result in lost messages and allows for automatic retries.
Outbox Lifecycle
The core_loop manages outbox transitions. Messages move from Queued to Sending and finally to Sent or Failed.
- SendMessage Event: Triggered by the UI, this event creates an
OutboxItemand persists it to theOutboxStore. - DrainOutbox: The core regularly checks for the oldest queued item and attempts dispatch.
- Retry Logic: If a transient error occurs, the system increments the attempt count and requeues the item until
MAX_OUTBOX_AUTO_ATTEMPTSis reached.
Sources: crates/mailiner-app/src/core_event.rs:1075-1150, crates/mailiner-app/src/core_event.rs:1178-1215
Dispatch State Machine
The following sequence diagram shows the interaction between the application core and the SMTP connector during dispatch:
SMTP Connection Management
The SmtpConnector handles the low-level SMTP protocol communication. It supports different security modes and authentication mechanisms.
Security and Authentication
The connector ensures that authentication never happens over a plaintext connection. If a plaintext stream is provided, it performs a STARTTLS handshake before proceeding to AUTH.
| Security Mode | Description |
|---|---|
| Implicit TLS | Connection is wrapped in TLS (via rustls) immediately upon opening (typically port 465). |
| STARTTLS | Connection starts as plaintext; EHLO is sent, followed by STARTTLS command and TLS upgrade (typically port 587). |
| AUTH PLAIN/LOGIN | Supported authentication mechanisms. The connector selects PLAIN if available, otherwise LOGIN. |
Sources: crates/mailiner-smtp-connector/src/lib.rs:165-195, crates/mailiner-smtp-connector/src/lib.rs:214-235
Error Classification
SMTP errors are classified into categories to determine if a retry is appropriate.
- Transient: (e.g., 4xx codes) Errors that might be resolved by retrying later.
- Permanent: (e.g., 5xx codes) Errors indicating the message will never be accepted (e.g.,
MessageTooLarge,RecipientRejected). - Security/Auth: Errors related to TLS handshake or invalid credentials.
Sources: crates/mailiner-smtp-connector/src/lib.rs:260-300
Archiving Sent Messages
Upon successful SMTP submission, Mailiner attempts a best-effort archive of the message to the IMAP "Sent" folder.
The ArchiveSent event triggers an APPEND operation on the IMAP server. The RFC 822 bytes sent via SMTP are reused for this operation. This process is decoupled from the SMTP transaction; a failure to archive the message does not rollback the successful send, but it does trigger a UI warning.
Sources: crates/mailiner-app/src/core_event.rs:1340-1375
Summary
The SMTP Session & Dispatch module provides a robust pipeline for email delivery. By separating message preparation (MIME), persistence (Outbox), and transport (SMTP Connector), it ensures that emails are correctly formatted and reliably delivered even in the face of network instability. The inclusion of a best-effort IMAP archive ensures that the user's sent history remains synchronized across clients.