How should an AI agent handle bounces and complaints?
Treat a bounce or a complaint as final. On Unitpost a hard bounce or a complaint puts the address on your suppression list, and every later send to it is skipped and reported as failed with last_event email.suppressed, without counting against your quota. An agent should read that as done, never retry it or remove the suppression itself, and tell a person when bounces climb.
Unitpost ·
Bounces and complaints are the two signals mailbox providers judge a sender by. A person notices them slowly. An agent that keeps sending can turn a few into a pattern within an hour, so the rules have to be in the code and the agent's instructions, not in its judgment.
What happens after a bounce or a complaint?
- A hard bounce (
bounce.type: "Permanent"): the address doesn't exist or refuses mail. You get anemail.bouncedwebhook, and the address joins your suppression list with originbounce. - A complaint: the recipient pressed "Report spam". You get
email.complained, and the address joins the list with origincomplaint. - A soft bounce (
Transient): a full mailbox or a temporary refusal. The sending service retries;email.bouncedarrives only if the retries run out.
Every later send to a suppressed address is skipped before it reaches anyone. The send reports status: "failed" with last_event: "email.suppressed", and an email.suppressed webhook fires. A skipped recipient isn't counted toward your quota.
What should the agent do with a skipped send?
Read failed together with last_event:
email.suppressed: final. Don't retry, don't try another address you guessed, don't send from another domain. Report it as "not sent: the address bounced or complained before".email.bouncedwithPermanent: final for that address. If the address came from a form, ask the person to correct it.email.complained: stop all mail to that person. A complaint suppresses the address for every send, receipts and resets included, unlike an unsubscribe from a marketing topic, which still lets transactional mail through.- Any other
failed: read the error and decide; this is the only kind a retry might fix.
Put rules 1–3 in the agent's instructions word for word. A model asked to "make sure the email gets through" will otherwise try exactly the workarounds that get a domain blocked.
Who decides when to unsuppress?
A person. The address leaves the list only when the recipient confirms it works or asks to hear from you again. Give agents a key without suppressions:write (which permissions), so the decision can't be made in a loop. Reading the list (suppressions:read) is fine and useful: an agent can check an address before it drafts a message nobody will receive.
When should the agent raise an alarm?
Rates matter more than single events. Gmail asks bulk senders to keep the spam rate under 0.3%, and a bounce rate above a few percent usually means a list problem, not bad luck. An agent that sends or reports can watch both:
- count
email.bouncedandemail.complainedagainst sends per day, from the webhooks oremail_stats; - stop a campaign it started (pause it) when complaints cross your threshold, and tell a person;
- send a weekly summary of new suppressions by origin (a report agent).
How do you test this before it matters?
Send to your own test addresses first, then check that the agent reads a suppressed result as final: suppress a test address by hand, ask the agent to email it, and confirm it reports "not sent" instead of trying again. The testing guide covers the rest of the cases.