Treat email as an external dependency, not a function call that always succeeds.

A useful design separates message creation, submission, provider response, asynchronous delivery events and business state.

Plan for failure

A successful API call or SMTP 250 usually means the next system accepted responsibility. It does not prove the recipient read the message—or even that final delivery has happened.

Queue application sends where appropriate, use bounded retries, avoid duplicate business actions, and keep a correlation identifier.

Identity

Define which domain appears in From, which domain handles bounces, and where DKIM signing happens. Do this before multiple applications invent their own patterns.

Reference material