Why your AI agent's mail lands in spam: 5 causes to check in order
AI agent emails going to spam? Check the authentication header, DNS records, domain age, content, and bounce rates in that order to find the layer that fails.
- engineering
- deliverability
- spf-dkim-dmarc
- custom-domains
- ai-agents

TL;DR
When an AI agent's email lands in spam, the cause is usually one of five things. Authentication is broken, the domain is too new, the content looks wrong, volume ramped too fast, or the agent sends from a shared domain. Check them in that order and you find the failing one quickly instead of guessing for days.
Your agent sends a message, the API says it was accepted, and the recipient never sees it. It went to their spam folder. Nothing in your logs looks wrong, because from your side nothing failed. The receiving mail server made a judgment about whether to trust the sender, and it said no.
That judgment is made from a handful of signals. Some are technical records you publish in DNS. Some are history the mailbox provider has built up about your domain. Some are about the message itself, and some are about how fast you started sending.
Agents make several of these worse. They start on brand new domains. They send at machine speed from day one. They spread mail across many addresses at once. Below is the order to check each signal in, what the check looks like, and what to change when it fails.
The short answer: check five things in order
Start with the evidence in a real spammed message, then work from the cheapest fix to the slowest. Authentication comes first because a missing or broken record is the most common cause and the fastest to fix. Domain reputation comes second because it explains why a correctly configured new domain still struggles. Content, sending volume, and the choice of sending domain come after that.
The order matters because the layers stack. A perfect message from an unauthenticated domain still gets filtered. Suppose a fully authenticated domain sends 2,000 cold emails on its first day: it gets filtered too. Rewriting templates while the DKIM record is missing doesn't fix anything. Work down the list.
Symptoms and the check that matches each one
Most spam problems announce themselves with a recognizable symptom. The table maps each symptom to the likely layer and the first check. Then skip to that section.
| What you see | Likely layer | First check | Usual fix |
|---|---|---|---|
| spf, dkim, or dmarc not pass in the header | Authentication | Domain record status in the console or API | Publish or correct the DNS record |
| All three pass, domain is weeks old | Reputation | Domain age and daily send volume | Slow down and follow a warmup schedule |
| Some messages land, similar ones do not | Content | Plain text part, links, images, subject line | Send text with HTML, cut links in first touch |
| Placement got worse after a volume jump | Volume and list quality | Rolling bounce and complaint rates | Remove bounced addresses, cut daily volume |
| Sending from @agentmail.to in production | Shared domain | Which domain the inbox sends from | Move the agent to your own custom domain |
Read the Authentication-Results header before touching DNS
One spammed message tells you more than any dashboard. Start there. Send a test to a Gmail account you own and open it. Choose Show original from the message menu. Gmail prints a summary of the SPF, DKIM, and DMARC results above the raw headers, so a first pass takes seconds rather than a careful read of every line.
The line to read is Authentication-Results, a header the receiving server adds to record what it checked. Each protocol gets pass, fail, softfail, or none. If DMARC says fail, look at which domain each check ran against, because that's usually where the answer is. DMARC passes only when SPF or DKIM passes for the domain in the From address. That match is called alignment.
Three results cover most cases, and each one points somewhere different. Any fail or none means the problem is authentication and the next section applies. All pass means authentication is fine and the cause is further down the list. A pass on a domain you don't recognize is a surprise path. Look for a forwarding rule or a second sending service.
Fix SPF, DKIM, and DMARC on the sending domain
These three records are how a domain proves its mail is real. Receivers check all of them. SPF, the Sender Policy Framework, is a DNS record listing the servers allowed to send for the domain. DKIM, DomainKeys Identified Mail, is a signature on each message. It proves the mail came from your domain unchanged. DMARC is a record that tells receivers what to do when the other two fail, and where to send reports.
AgentMail generates all three when you add a custom domain. The SPF record is v=spf1 include:agentmail.to ~all. DKIM is a TXT record under a selector host. DMARC defaults to p=reject. You publish them at your DNS provider and verify the domain.
A common mistake is a second SPF record. A domain can have only one. If Google Workspace already publishes SPF, add include:agentmail.to to that record instead. The domain API flags this case. A record with the reason duplicate_records has the right value, plus extra records at the same name.
Google's sender guidelines set the floor for Gmail recipients. Every sender needs SPF or DKIM. Above 5,000 messages a day to Gmail accounts, you need all three, with the From domain aligned. Valid reverse DNS and TLS are required too.
Before you change anything, pull the record status from the API. That way you fix the record that's actually broken, not the one you suspect.
Python
# pip install agentmail==2.0.14from agentmail import AgentMailclient = AgentMail(api_key="am_live_your_key")domain = client.domains.get(domain_id="yourcompany.com")print(domain.domain, domain.status, domain.reason)for record in domain.records: print(record.type, record.name, record.status, record.reason or "")# Example output:# yourcompany.com INVALID dns_records_invalid# TXT @ INVALID duplicate_records# TXT selector._domainkey VALID# TXT _dmarc VALIDA domain status of VERIFIED with every record VALID rules this layer out. Records also go stale when someone edits DNS for an unrelated reason. Run this check on a schedule, not once at setup and never again, because a deleted record can stop the domain from sending or receiving.
Check domain age and sender reputation
Mailbox providers track reputation per domain, and a new domain starts with none. Nobody has seen it send yet. Hundreds of messages on day one look like a spammer with a fresh domain. Providers filter that pattern even when every record passes.
Warmup is the fix. It takes weeks. The domain warming schedule starts at 10 to 20 emails a day for days 1 to 3. Days 4 to 7 move to 50 to 100 a day. Days 22 to 30 reach 1,000 to 5,000 a day. Send the earliest messages to the recipients most likely to reply, because replies build reputation faster than one way sends.
Agents have one advantage here, and it comes from how cheap inboxes are. Ten inboxes sending 10 messages each look more natural than one inbox sending 100, and creating inboxes is one API call each. Running cold outreach sequences too? Warmup services like Instantly and Smartlead connect to AgentMail inboxes over SMTP.
Content that filters still score after authentication passes
A message from a well authenticated domain with a good history can still be filtered for what it contains, even when nothing else about the sender has changed. This layer usually shows up as inconsistent placement: one template lands and a near copy does not.
Send a plain text part with every HTML message, because HTML with no text version is a classic spam signal. Avoid all caps subjects, strings of exclamation marks, and words like FREE or ACT NOW. Keep links few, especially in the first message of a conversation, and save the call to action for after the recipient replies. Large images with little text count against you. So does an open tracking pixel, since it's an image in the body.
Agents add one risk that templates don't. A model that writes each message fresh can drift into sales language. Sample real outgoing messages every week. Don't trust the prompt alone.
Volume ramp, bounces, and complaints
Bounces and complaints are the fastest way to lose a domain. Both are visible. A bounce is a message the receiving server refused, usually because the address does not exist. A complaint is a recipient pressing the spam button. Both tell providers you are mailing people who did not ask for it.
The healthy ranges are a bounce rate under 2 percent and a complaint rate under 0.1 percent. Slow down at once if bounces pass 5 percent. Google asks bulk senders to keep the spam rate shown in Postmaster Tools below 0.10 percent and never reach 0.30 percent. AgentMail's account moderation watches the rolling 24 hour bounce rate once 1,000 messages were sent in the window. It warns at 5 percent and suspends at 10 percent.
The same rolling rate is available from the API. An agent can check it before a batch goes out and hold the batch when the number climbs.
Python
# pip install agentmail==2.0.14from datetime import datetime, timedelta, timezonefrom agentmail import AgentMailclient = AgentMail(api_key="am_live_your_key")# Omitting rate_types returns both bounce and complaint ratesrates = client.metrics.query_rates( start=datetime.now(timezone.utc) - timedelta(days=7), period=86400, window=86400,)for rate_type, points in rates.items(): for point in points: rate = "n/a" if point.rate is None else f"{point.rate:.2%}" print(rate_type, point.timestamp.date(), rate, "sent:", point.sent)# Example output:# bounce 2026-10-08 3.10% sent: 1240# complaint 2026-10-08 0.08% sent: 1240Rates tell you something went wrong. Events tell you which address caused it, and you'll want both. Subscribe to bounce and complaint events. Then remove those addresses from every list, memory store, and CRM sync the agent can reach, so a later run never picks them up again.
Python
# pip install agentmail==2.0.14from agentmail import AgentMailclient = AgentMail(api_key="am_live_your_key")webhook = client.webhooks.create( url="https://agents.yourcompany.com/hooks/agentmail", event_types=["message.bounced", "message.complained"], client_id="deliverability-alerts",)print(webhook.webhook_id)# Example output:# wh_2f6c9a1eEach bounce event carries the inbox, the message, a bounce type, and the recipient addresses that failed, which is enough to suppress the address and trace exactly which agent sent to it. Nothing more is needed.
Shared @agentmail.to or your own domain
The shared @agentmail.to domain is for testing. Only testing. Every user who sends from it shares its reputation. Other senders affect your placement, and you can't repair it. That's fine for a demo and a liability for a product. Production agents belong on a custom domain you control, and the Developer plan includes 10 of them, which covers a primary domain plus several isolated sending domains.
Separate domains also keep one agent's mistakes from spreading to the agents whose mail has to arrive, like receipts and invoices. A billing agent sending receipts and an outreach agent sending cold email carry very different risk. On one domain, the outreach agent drags down the receipts. Register billing.yourcompany.com and outreach.yourcompany.com each as its own domain. Each then gets its own DKIM identity and reputation. Enabling subdomains on a parent domain is different. Those inboxes send under the parent's identity and share its reputation.
The custom domains guide for agent fleets covers verifying domains and spreading inboxes across them. Email Deliverability 101 explains why each layer carries its weight. To act on bounce events as they arrive, read building real-time agents with webhooks. More engineering posts are on the AgentMail blog.
What AgentMail does not do
AgentMail can't give a new domain a reputation it hasn't earned, and it can't fix the shared @agentmail.to domain for you. Warmup still takes weeks, and production still needs your own domain. It does not validate addresses before you send or clean your lists, which means bounces and complaints stay your responsibility. Gmail's spam rate lives in Google Postmaster Tools, which you set up for your own domain separately.




