Email that arrives
A welcome message, sent once when an account is first used, and a notice to somebody a document has been shared with.
Both took three attempts. The notice was wired to an endpoint the app never calls, then fired after the response so the request never left the function, then blocked by a key that was genuinely absent from the first builds. Deliverability needed DMARC, not just SPF and DKIM.
Mail from a product is mostly a thing to be suspicious of, so it is worth saying how little of it there is here. Two messages: a welcome, the first time an account is actually used, and a notice to somebody an account has shared a document with. No digests, no product news, nothing you have to unsubscribe from.
Why they were not arriving
Three faults, one after the other. The notice was first wired to an endpoint the application never calls. Then it was fixed to fire after the response had gone out — which is the natural thing to write and the wrong thing in a serverless function, because the platform may freeze the instance the moment a response is sent, and a request that has not left yet never does. Three addresses were added on a live deployment and the mail provider logged nothing at all: not a failure, an absence.
So a send is now part of the request that triggered it, and awaited, with a four-second timeout so a provider having a bad minute cannot turn a share into a slow share. The third fault was duller than the other two: the key was genuinely missing from the first builds.
Why they were going to spam
SPF and DKIM were in place from the start and were never the problem. The record that was missing was DMARC — the DNS entry that says what a receiver should do with mail failing the other two — and a young domain sending automated mail without it is treated harshly. That is DNS rather than code, which is part of why it took three attempts to find.
What the code can do is not make it worse. Both MIME parts rather than text alone, because text-only automated mail from a domain with no sending history is what a filter distrusts most. A subject that leads with the document's name instead of a raw address beside a quoted filename, a pair whose shape filters know. And a Reply-To pointing at the person who shared it, because a message you cannot answer reads as machinery.
What these messages are not
No images and no tracking pixel; the HTML part is the same words as the plain part, rendered by the product's own converter. A document's name is printed inside a code span, so a file called [Confirm your account](https://elsewhere.example) arrives as text rather than as a live link in a message carrying our signature. A deployment with no key configured sends nothing and says nothing, and a share that worked is never reported as failed because the mail was not. All of it is in English whatever your language: it goes to an address we know nothing else about.
Related: sharing a document as a link, and whether an online converter is safe.