Getting Started

Upgrading to v3

This guide walks you through upgrading an existing v2.0 deployment to v3.0 without changing how mail is accepted. The only required change is pointing MailLaser at a Cedar policy file. Once the binary is running, you can opt into v3's new capabilities one at a time.


What changed

v3.0 adds four capability surfaces and one required config variable.

ChangeImpactRequired action
Cedar authorizationEvery message is now evaluated against a policy file.Create a policy file and set MAIL_LASER_CEDAR_POLICIES.
AttachmentsEmails with attachments are now parsed and forwarded (inline or to S3).None. Default inline mode keeps payloads self-contained.
DMARC validationOptional gate that can reject spoofed From: at the SMTP layer.None — defaults to off.
Webhook signingOptional HMAC-SHA256 header on every outbound request.None — off unless MAIL_LASER_WEBHOOK_SIGNING_SECRET is set.
EHLO SIZEMailLaser now advertises SIZE and rejects oversized messages with 552.None — default cap is 25 MiB; increase MAIL_LASER_MAX_MESSAGE_SIZE if needed.
Connection hardeningPer-IP concurrent-session cap (default 10) and per-session unknown-RCPT TO cap (default 3, replies 421 and closes the socket on the Nth unknown) silently bound abusive traffic.None for normal senders. Raise MAIL_LASER_MAX_CONCURRENT_PER_IP or MAIL_LASER_MAX_UNKNOWN_RCPTS_PER_SESSION, or set either to 0 to disable, if you run unusual probing patterns.

The payload schema gains three optional fields (attachments, dmarc_result, authenticated_from) that are absent from v2-style payloads and appear only when the corresponding feature is enabled. Existing consumers that ignore unknown fields are unaffected.


If you pin to :latest

The ghcr.io/govcraft/mail-laser:latest tag is frozen on the final v2 image for the duration of the v3 migration window. A restart of a v2 container pinned to :latest will NOT pull v3 and will continue running the v2 binary you already trust.

To actually upgrade, follow Steps 1–2 below (create a Cedar policy and point MailLaser at it), then change your image pin from :latest to one of:

  • ghcr.io/govcraft/mail-laser:3 — tracks the v3 major line and auto-updates on patch and minor releases.
  • ghcr.io/govcraft/mail-laser:3.0.0 — pins to an exact version.

Do not rely on :latest to deliver v3. Once enough v2 deployments have migrated, :latest will be promoted to v3 via a registry-side retag — but not on a fixed schedule, and not before giving operators time to opt in deliberately.


Step 1: Write a v2-compatible Cedar policy

Create a file at /etc/mail-laser/policies.cedar (or wherever you prefer) containing:

permit(principal, action == Action::"SendMail", resource);
permit(principal, action == Action::"Attach", resource);

This accepts every sender and every attachment, matching v2.0's behavior. You can tighten it later — see Authorization for how.


Step 2: Point MailLaser at the policy

Add one environment variable:

MAIL_LASER_CEDAR_POLICIES=/etc/mail-laser/policies.cedar

If you run MailLaser in Docker, also mount the policy file into the container. See Docker for the full compose snippet.

At this point your deployment behaves identically to v2.0 — accept the same mail, forward the same payload shape — with attachments now passing through as well.


Step 3 (optional): Opt into DMARC

If your MailLaser instance sits behind a public MX, enable DMARC to stop spoofed From: headers:

MAIL_LASER_DMARC_MODE=monitor   # start in monitor to observe outcomes

Monitor mode annotates each payload with a dmarc_result field without rejecting anything. After watching a few days of real traffic, switch to enforce to actually reject failures. See DMARC validation.


Step 4 (optional): Opt into webhook signing

If you want your receiver to verify each delivery came from MailLaser:

MAIL_LASER_WEBHOOK_SIGNING_SECRET=<a-high-entropy-secret>

Every request will then carry X-MailLaser-Timestamp and X-MailLaser-Signature-256 headers. See Webhook signing for the verification recipe.


Step 5 (optional): Move large attachments to S3

Inline delivery base64-encodes attachment bytes into the JSON payload, which inflates payload size by roughly 33% and caps out at the message-size limit. For large files or many attachments, upload to an S3-compatible bucket instead:

MAIL_LASER_ATTACHMENT_DELIVERY=s3
MAIL_LASER_S3_BUCKET=mail-laser-inbound
MAIL_LASER_S3_REGION=us-east-1

See Attachments for the full set of S3 options and presigned-URL behavior.


Verifying the upgrade

After restarting, check that:

  • Startup logs show Config: Using cedar_policies_path: ... and no "missing variable" errors.
  • A test email sent via swaks is accepted and forwarded.
  • The webhook payload contains the same fields as before. New optional fields (attachments, dmarc_result, authenticated_from) appear only if you enabled the corresponding feature.

If you enabled DMARC in monitor mode, every payload should carry a dmarc_result field — pass, fail, none, or temperror. If you enabled signing, every webhook request should carry both X-MailLaser-Timestamp and X-MailLaser-Signature-256 headers.

Previous
Installation