Answer each request with a
2xx, including for messages you decide to drop. The mail has already been accepted by the time it reaches your endpoint, so an error response can’t reject it back to the sender. It only makes the delivery to your endpoint look failed.What You Have to Work With
Your forwarding URL receives a JSON array of events. Each event carries one message inevent.msys.relay_message (see Email Parsing for the full payload). The fields that matter for spam handling are:
Both sender fields are set by whoever sent the message, so treat them as claims, not proof of identity.
Headers come as an array like
[{ "Received": "..." }, { "Subject": "..." }], and a name can appear more than once. A small helper makes them easier to read:
Check Authentication Results
Some messages carry anAuthentication-Results or Received-SPF header, added by a mail server that checked SPF, DKIM or DMARC along the way. Don’t assume these headers are present, and remember that a sender can put a fake one in their own message. Use them as one signal among several, never as the only check.
Build Your Own Heuristics
A simple approach is to add up points for suspicious signals and act on the total. The point scale below belongs to this example code. It isn’t a Lettr score, so tune the weights and thresholds to your own traffic.content.email_rfc822 to a third-party spam filter. When content.email_rfc822_is_base64 is true, base64-decode it first.
Allow and Block Lists
Keep your own lists of trusted and blocked senders, for example in your database, and check them before any other rule:Rate Limiting by Sender
Limit how many messages one sender or sender domain can push through your pipeline:RateLimiterMemory counts per process. If you run more than one instance of your handler, use a shared store such as Redis.
Quarantine in Your Own Storage
Lettr doesn’t keep inbound messages, so a quarantine has to live in your own storage. Key each record on theMessage-ID header, which also lets you ignore a message that arrives twice:
Learning From Reports
When spam gets through, let your users report it and add the sender to your blocklist:Best Practices
Quarantine before you drop
Quarantine before you drop
Start by quarantining suspicious mail instead of discarding it. Once you know your false positive rate, you can drop the clearest cases.
Log every decision
Log every decision
Record why each message was allowed, quarantined or dropped. Lettr doesn’t keep a copy of inbound mail, so your logs are the only way to trace a missing email.
Combine multiple signals
Combine multiple signals
No single check is reliable on its own. Combine allow and block lists, authentication results when present, rate limits and content rules.
Do slow checks asynchronously
Do slow checks asynchronously
Answer the request quickly and run expensive checks, such as a third-party filter, from a queue.
Review the quarantine regularly
Review the quarantine regularly
Release false positives promptly and use them to tune your rules.
Related Topics
Email Parsing
The full inbound payload
Routing
Route emails in your handler
Security
Security best practices
Best Practices
Overall inbound best practices