M25 — Sending abuse reports: a send queue, and optional SMTP
Status: accepted. Changes a decision of M22 (“the stack never sends mail and stores no mail credentials”): the owner asked for optional sending. Default behaviour is unchanged: nothing is sent until the owner configures SMTP in the dashboard and picks a sending mode.
1. Send queue (always available)
Section titled “1. Send queue (always available)”A “To send” view on the Abuse reports page walks through the reports that are ready (guard
passed, settings complete, status draft or reviewed), one at a time:
- recipient, subject and body with copy buttons;
- “Open in mail app”: a
mailto:link with recipient and subject, and the body when the whole link stays under 1,800 characters. The full plain-text body is copied to the clipboard on click in every case, so a long report is one paste away; - “Sent, next” marks it sent (existing route) and opens the next one; keyboard shortcuts;
- a reminder on top: connect to your mailbox through your VPN and check the sender address. Help explains how to make Proton Mail the browser’s handler for email links.
Free Proton addresses have no SMTP access: the queue is the way to use them.
2. Optional SMTP for reports
Section titled “2. Optional SMTP for reports”2.1 Settings (Settings > Reporting > Sending)
Section titled “2.1 Settings (Settings > Reporting > Sending)”One profile, stored in table report_smtp (single row, migration 0022): host, port, security (starttls|ssl), username, from_address, from_name, password (AES-GCM with the existing SecretBox, never returned), mode, auto_hold_minutes, daily_cap, updated_at, updated_by.
- Write routes (
PUT,DELETE /api/v1/abuse/smtp) are admin-only, CSRF, and ask for the password again.GETreturns everything except the password (password_set: bool). hostis a DNS name (no IP literal, no internal name);port1-65535; plain text is not an option. A “Proton (paid plan, custom domain)” preset fillssmtp.protonmail.ch, 587, starttls, and says that the password is an SMTP token from Proton’s settings.from_namedefaults to empty.from_addressandfrom_namego through the identity guard like every report (a term that points to the owner refuses the profile with a guard code).
2.2 Modes
Section titled “2.2 Modes”| mode | behaviour |
|---|---|
off (default) | nothing is sent; the queue of section 1 only |
click | a “Send now” button on a ready report sends it after a confirmation dialog |
auto | ready reports are sent automatically after auto_hold_minutes (default 60, 10 to 1440); while waiting they show “Sending at hh:mm” with Cancel. At most daily_cap (default 20, 1 to 200) per UTC day |
Demo reports are never sent. A report whose guard fails, or with incomplete settings, is never sent in any mode.
2.3 How a mail leaves
Section titled “2.3 How a mail leaves”The API never talks SMTP (it has no route out). It writes a row in abuse_send_requests
(id, report_id NULL for a test, kind: send|test, requested_by, requested_at, status: pending|sent |failed|cancelled, error_code, done_at). The ingest abuse worker:
- waits while the egress gate is closed (the request stays pending);
- re-renders the report from the stored evidence and runs the identity guard on the complete
message, headers included; any failure →
failedwith the guard code, nothing sent; - sends through
suckerpot_egress(TunnelSMTP, the VPN proxy), TLS with certificate checks; - on success sets the report to
sent(sent_via = 'smtp',sent_at), on failure keeps it ready and records a short error code (auth_failed,tls_failed,refused,timeout,egress_closed,guard_failed).
Message hygiene: From: from_name <from_address>, To: the abuse mailbox only, no Cc/Bcc,
the rendered Subject, Date in UTC, a Message-ID on the sender’s domain with a random local
part, no X-Mailer/User-Agent, the X-ARF parts as rendered by M22. The SMTP EHLO name is
never the container’s host name: it is the domain of from_address. The same EHLO rule is
applied to the alerts’ SMTP client.
“Send a test” sends a short neutral message to from_address itself.
2.4 Audit
Section titled “2.4 Audit”abuse.smtp.update, abuse.smtp.delete, abuse.send (report id, mode), abuse.send.cancel,
abuse.smtp.test. Never the password, never the message body.