Core Concepts
SMTP server
MailLaser runs a lightweight SMTP server that accepts incoming email connections, validates recipients against your configured list, and passes parsed email data to the webhook delivery system.
Supported SMTP commands
MailLaser implements the essential SMTP commands needed to receive email:
| Command | Description |
|---|---|
EHLO / HELO | Initiates the SMTP session. EHLO advertises STARTTLS and the configured SIZE limit. |
STARTTLS | Upgrades the connection to TLS encryption. |
MAIL FROM | Specifies the sender's email address. |
RCPT TO | Specifies the recipient. Validated against MAIL_LASER_TARGET_EMAILS. Cedar authorization runs later, at end-of-DATA. |
DATA | Begins the email content transfer. Ends with a line containing only . |
QUIT | Closes the connection. |
Commands are case-insensitive. MAIL FROM, mail from, and Mail From are all accepted.
Session lifecycle
A typical SMTP session follows this sequence:
Client connects
Server: 220 MailLaser SMTP Server Ready
Client: EHLO mail.example.com
Server: 250-MailLaser greets mail.example.com
Server: 250-SIZE 26214400
Server: 250 STARTTLS
Client: MAIL FROM:<sender@example.com>
Server: 250 OK
Client: RCPT TO:<alerts@myapp.com>
Server: 250 OK
Client: DATA
Server: 354 Start mail input; end with <CRLF>.<CRLF>
Client: (email headers and body)
Client: .
Server: 250 OK: Message accepted for delivery
Client: QUIT
Server: 221 Bye
After the DATA phase completes, the state resets to Greeted, allowing the client to send additional emails on the same connection without reconnecting.
Recipient validation
When a RCPT TO command arrives, MailLaser compares the recipient address against the list in MAIL_LASER_TARGET_EMAILS using a case-insensitive match.
- No target match: Responds with
550 No such user here. - Target match: Responds with
250 OK. CedarSendMailevaluation is deferred until end-of-DATA so the DMARC outcome can feed the authorization context; see Authorization.
If no valid recipient has been accepted, the DATA command is rejected with 503 Bad sequence of commands.
Size limit and EHLO SIZE
MailLaser advertises the configured message size cap through the SMTP SIZE extension. The EHLO response includes a 250-SIZE <bytes> line matching MAIL_LASER_MAX_MESSAGE_SIZE (default 25 MiB). Well-behaved senders check this before transmitting data and decline oversized messages themselves.
Messages that exceed the cap at end-of-DATA are rejected with 552 5.3.4 Message size exceeds limit. Individual attachments above MAIL_LASER_MAX_ATTACHMENT_SIZE trigger 552 5.3.4 Attachment exceeds size limit. In both cases, no webhook is sent.
DMARC and Cedar reply codes
DMARC validation (when enabled) and Cedar authorization both run at end-of-DATA. Either can produce these reply codes:
| Condition | Reply | Action |
|---|---|---|
DMARC fail (enforce mode) | 550 5.7.1 DMARC policy violation | Message rejected. |
DMARC temperror (enforce mode, MAIL_LASER_DMARC_TEMPERROR_ACTION=reject) | 451 4.7.0 DMARC temporary error | Sender retries. |
Cedar SendMail denial | 550 5.7.1 Sender not authorized | Message rejected. |
Cedar Attach denial | 550 5.7.1 Attachment not permitted by policy | Message rejected. |
DMARC evaluates first, so a DMARC failure rejects before Cedar runs. When DMARC passes or is off, Cedar's SendMail evaluation receives the DMARC outcome as context; see DMARC validation and Authorization.
STARTTLS
MailLaser supports STARTTLS to encrypt SMTP connections. When a client sends EHLO, MailLaser advertises STARTTLS as a capability. The client can then issue STARTTLS to upgrade the connection.
MailLaser generates a self-signed TLS certificate at runtime using the rcgen crate. No certificate files need to be configured or managed. The certificate uses localhost as the subject alternative name.
Self-signed certificates
Because the certificate is self-signed, sending mail clients must either accept self-signed certificates or skip certificate verification. This is appropriate for internal deployments but not suitable for receiving mail from arbitrary internet senders that enforce strict TLS validation.
The STARTTLS flow:
- Client sends
STARTTLS - Server responds with
220 Go ahead - TLS handshake occurs using
tokio-rustls - After successful handshake, the session continues over the encrypted connection
- The client must send
EHLOorHELOagain to re-establish the session
If a client attempts STARTTLS when TLS is already active, the server responds with 503 STARTTLS already active.
Email parsing
Once the DATA phase completes, MailLaser parses the raw email using the mailparse crate. The parser handles:
- Subject: Extracted from the
Subject:header. Defaults to an empty string if not present. - Sender name: The display name from the
From:header (e.g., "John Doe" fromJohn Doe <john@example.com>). Omitted from the payload if not present. - Plain text body: Preferred from the
text/plainMIME part. If onlytext/htmlis available,html2textgenerates a plain-text conversion. - HTML body: The raw
text/htmlMIME part, if present. Omitted from the payload if the email is plain text only. - Matched headers: Any headers matching the configured
MAIL_LASER_HEADER_PREFIXprefixes. See Header passthrough.
The parser handles both simple single-part emails and multipart/alternative messages. It processes MIME subparts recursively, extracting the first text/plain and text/html parts it finds.
Attachments
MailLaser parses MIME attachments and forwards them alongside the text body. Attachments can be delivered inline (base64 in the JSON payload) or uploaded to an S3-compatible bucket. See Attachments.
Connection handling
Each incoming TCP connection is handled in a separate Tokio task, so concurrent connections do not block each other. The SMTP listener actor uses the acton-reactive framework with a Permanent restart policy, meaning it automatically recovers from unexpected failures.
To bound the bandwidth an abusive peer can consume before end-of-DATA authorization runs, MailLaser caps concurrent connections per source IP via MAIL_LASER_MAX_CONCURRENT_PER_IP (default 10). Over-cap connections are dropped at TCP accept without an SMTP greeting — no session task is spawned and no resources are consumed beyond the dropped socket. Set to 0 to disable.
Within an accepted session, MAIL_LASER_MAX_UNKNOWN_RCPTS_PER_SESSION (default 3) bounds recipient-address enumeration. Unknown RCPT TO addresses get the standard 550 No such user here, but after N unknowns in one session the server replies 421 4.7.0 Too many unknown recipients, closing connection and closes the socket. Combined with the per-IP connection cap, this makes probing the target allowlist linearly expensive in connections. Set to 0 to disable.
The server uses tokio::select! to listen for new connections while also monitoring a cancellation token, enabling graceful shutdown when the application receives a termination signal.
No authentication
MailLaser does not implement SMTP authentication (SMTP AUTH). Security relies on network-level controls:
- Bind to a specific interface using
MAIL_LASER_BIND_ADDRESS(e.g.,127.0.0.1for local-only access) - Use firewall rules to restrict which hosts can connect to the SMTP port
- Place MailLaser behind a reverse proxy or VPN for production deployments exposed to the internet
The recipient validation provides application-level filtering: only emails addressed to your configured targets are processed.