Stop Bounces Before They Happen

MultiMail scores every recipient domain against MX records, SPF, DMARC, and platform-wide bounce history before your agent sends a single message.


Why this matters

High-volume AI agents sending to stale or invalid addresses accumulate bounces rapidly. Hard bounces above 2% trigger ISP throttling and can blacklist your sending domain within days. The damage is not isolated — in a shared infrastructure environment, one agent's bounce spike degrades deliverability for every tenant on the platform. Traditional approaches catch bounces after the fact. By then the reputation hit has already landed, and unwinding a blacklisting takes weeks of remediation that no agent can automate away.


How MultiMail solves this

MultiMail evaluates recipient domain health before send_email executes. Each domain receives a Green, Yellow, or Red classification based on live MX lookups, SPF and DMARC record validation, and aggregated bounce history from across the platform. Red domains are blocked at the API layer — the request returns a structured error before any message enters the queue. Yellow domains are flagged in the response with specific signal breakdowns so your agent can decide whether to proceed or defer. Bounce webhooks fire on every delivery failure, carrying SMTP diagnostic codes and suppression state so your agent can update its contact list without polling or manual intervention.

1

Domain Intelligence on Every Send

Before queuing a message, MultiMail resolves the recipient domain's MX records, validates SPF and DMARC alignment, and checks platform-wide bounce history. The check runs in under 50ms and is transparent to your agent unless the domain is Yellow or Red.

2

Green / Yellow / Red Classification

Green domains pass all checks and send normally. Yellow domains have degraded signals — expired SPF, missing DMARC, or elevated bounce rates — and are flagged in the API response with a domain_signals array. Red domains are blocked outright; send_email returns a 422 with domain_blocked as the error code before the message is queued.

3

Automatic Suppression on Hard Bounce

When a hard bounce occurs (SMTP 5xx, invalid mailbox, domain not found), MultiMail fires a bounce webhook to your registered endpoint and adds the address to your tenant's suppression list. Subsequent send_email calls to that address return a SuppressedAddressError before consuming send quota.

4

Compound Platform Intelligence

Bounce data from all MultiMail tenants contributes to the platform-wide domain reputation model. A domain that begins bouncing across the platform is classified Red for every agent — you benefit from signals your own sends have not yet generated, before your first attempt to a degraded domain.

5

Pre-Send List Validation

Your agent can check suppression status and domain risk for a batch of addresses via the suppression/check endpoint before building a send list. This lets agents prune stale contacts during list preparation rather than discovering suppressions one by one mid-campaign.


Implementation

Send with Domain Classification Handling
python
import multimail
from multimail.exceptions import DomainBlockedError, SuppressedAddressError

client = multimail.Client(api_key="mm_live_...")

def send_with_domain_check(mailbox_id, recipient, subject, body):
    try:
        result = client.send_email(
            mailbox_id=mailbox_id,
            to=recipient,
            subject=subject,
            body=body,
        )
        if result.domain_risk == "yellow":
            "cm"># Flagged but not blocked — agent decides
            print(f"Yellow domain signals: {result.domain_signals}")
        return result

    except DomainBlockedError as e:
        "cm"># Red domain — blocked before send, zero bounce impact
        print(f"Blocked: {e.recipient} — reason: {e.reason}")
        return None

    except SuppressedAddressError as e:
        "cm"># Prior hard bounce — suppressed at platform level
        print(f"Suppressed: {e.recipient} — suppressed_at: {e.suppressed_at}")
        return None

result = send_with_domain_check(
    mailbox_id="mbx_01JDEF456",
    recipient="[email protected]",
    subject="Q2 update from Acme",
    body="Hi, wanted to share our Q2 summary with you.",
)

Handle Green, Yellow, and Red domain outcomes in your agent. Yellow domains surface a domain_signals array — your agent decides whether to proceed or defer.

Bounce Webhook Handler
javascript
import { createHmac } from 'crypto';

export async function handleBounceWebhook(req, res) {
  const sig = req.headers['x-multimail-signature'];
  const expected = createHmac('sha256', process.env.MM_WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest('hex');

  if (sig !== expected) {
    return res.status(401).json({ error: 'invalid_signature' });
  }

  const event = req.body;

  if (event.type === 'email.bounced') {
    const { recipient, bounce_type, smtp_code, message_id, suppressed_at } = event.data;

    if (bounce_type === 'hard') {
      "cm">// Platform has already suppressed this address.
      "cm">// Sync the event to your CRM or contact store.
      await markContactInvalid(recipient, {
        reason: 'hard_bounce',
        smtp_code,
        bounced_message_id: message_id,
        suppressed_at,
      });
      console.log(`Hard bounce suppressed: ${recipient} (SMTP ${smtp_code})`);
    } else if (bounce_type === 'soft') {
      "cm">// Temporary failure — platform will retry automatically.
      "cm">// Log for monitoring but no action needed.
      console.log(`Soft bounce on ${message_id}, smtp_code=${smtp_code}`);
    }
  }

  res.status(200).json({ received: true });
}

Process bounce events from MultiMail webhooks. Hard bounces are already suppressed by the platform; your handler syncs the event to your CRM or contact database.

Pre-Send List Validation via REST
bash
"cm"># Validate addresses before campaign send
curl -X POST https://api.multimail.dev/v1/suppression/check \
  -H "Authorization: Bearer $MULTIMAIL_API_KEY..." \
  -H "Content-Type: application/json" \
  -d &"cm">#039;{
    "addresses": [
      "[email protected]",
      "[email protected]",
      "[email protected]"
    ]
  }&"cm">#039;

"cm"># Response:
"cm"># {
"cm">#   "results": [
"cm">#     {
"cm">#       "address": "[email protected]",
"cm">#       "suppressed": false,
"cm">#       "domain_risk": "green"
"cm">#     },
"cm">#     {
"cm">#       "address": "[email protected]",
"cm">#       "suppressed": true,
"cm">#       "reason": "hard_bounce",
"cm">#       "domain_risk": "red",
"cm">#       "signals": ["no_mx_records", "platform_bounce_rate_exceeded"]
"cm">#     },
"cm">#     {
"cm">#       "address": "[email protected]",
"cm">#       "suppressed": false,
"cm">#       "domain_risk": "yellow",
"cm">#       "signals": ["missing_dmarc"]
"cm">#     }
"cm">#   ],
"cm">#   "suppressed_count": 1,
"cm">#   "sendable_count": 2
"cm"># }

Validate a batch of addresses for suppression status and domain risk before building a campaign. Prune Red and suppressed addresses before your send_email loop starts.

Autonomous Bounce-Safe Campaign Agent
python
import multimail
from multimail.exceptions import DomainBlockedError, SuppressedAddressError

client = multimail.Client(
    api_key="mm_live_...",
    oversight_mode="autonomous",
)

def run_bounce_safe_campaign(mailbox_id, contacts, subject, body_template):
    results = {"sent": [], "blocked": [], "suppressed": [], "yellow_flagged": []}

    for contact in contacts:
        try:
            result = client.send_email(
                mailbox_id=mailbox_id,
                to=contact["email"],
                subject=subject,
                body=body_template.format(name=contact["name"]),
            )
            if result.domain_risk == "yellow":
                results["yellow_flagged"].append({
                    "address": contact["email"],
                    "signals": result.domain_signals,
                })
            else:
                results["sent"].append(contact["email"])

        except DomainBlockedError as e:
            results["blocked"].append({
                "address": contact["email"],
                "reason": e.reason,
                "signals": e.domain_signals,
            })

        except SuppressedAddressError as e:
            results["suppressed"].append(contact["email"])

    print(f"Sent: {len(results[&"cm">#039;sent'])}")
    print(f"Blocked (red domain): {len(results[&"cm">#039;blocked'])}")
    print(f"Suppressed (prior bounce): {len(results[&"cm">#039;suppressed'])}")
    print(f"Flagged (yellow domain): {len(results[&"cm">#039;yellow_flagged'])}")
    return results

A complete agent loop that pre-validates addresses, handles domain blocks inline, and collects structured results for post-campaign reporting.


What you get

Pre-Send Blocking Eliminates Bounce Impact

Domain classification runs before send_email queues a message. Red domains never reach the mail server, contributing zero bounce rate to your sending domain's reputation.

Platform-Wide Bounce Intelligence

MultiMail aggregates bounce signals across all tenants. A domain that begins bouncing for one agent is classified Red for every agent — you benefit from signals your own sends have not yet generated.

Automatic Suppression with No Agent Overhead

Hard bounces trigger suppression automatically at the platform level. Subsequent send_email calls to suppressed addresses return a typed SuppressedAddressError before the request enters the queue, consuming no send quota.

Structured Errors for Agent Decision Logic

Every block or suppression surfaces a typed exception with machine-readable reason codes — domain_blocked, hard_bounce, soft_bounce, no_mx_records. Your agent routes, logs, or escalates without parsing human-readable strings.

Yellow Domain Transparency

Degraded but not blocked domains are surfaced with specific signal breakdowns: missing_dmarc, stale_mx, elevated_bounce_rate. Your agent receives the signal and makes the call — MultiMail does not silently drop borderline addresses.


Recommended oversight mode

Recommended
autonomous
Bounce management is a protective, reactive operation. The decisions are deterministic: Red domains are blocked, hard bounces are suppressed. There is no ambiguity that warrants human review, and adding an approval step introduces latency into a process that needs to complete before the next send attempt. Acting on a Red domain block is always less risky than waiting for human approval. Use autonomous mode so bounce suppression stays ahead of send volume at scale.

Common questions

What is the difference between a hard bounce and a soft bounce?
A hard bounce is a permanent delivery failure — the mailbox does not exist (SMTP 550), the domain has no MX records, or the receiving server explicitly rejects the address. MultiMail suppresses hard-bounced addresses automatically. A soft bounce is a temporary failure — mailbox full, server overloaded, or a transient connection timeout. MultiMail retries soft bounces on an exponential backoff schedule before treating them as permanent.
Does pre-send domain classification add latency to send_email calls?
The domain check adds under 50ms to the API response time. Results are cached per domain with a TTL tuned to DNS record volatility — MX records are cached longer than bounce-history signals. For high-throughput scenarios, pre-validate your send list via the /v1/suppression/check endpoint before your campaign loop rather than discovering blocks inline.
Can I see why a domain was classified Red?
Yes. The DomainBlockedError exception and the domain_signals field in the API response include the contributing factors as stable string codes: no_mx_records, spf_fail, dmarc_missing, platform_bounce_rate_exceeded, or blacklisted. These codes are suitable for logging and agent decision logic without string parsing.
How does MultiMail suppress addresses without my agent explicitly calling a suppression API?
Suppression is managed at the platform level. When a bounce event arrives from the receiving mail server, MultiMail records the suppression against your tenant automatically and fires a bounce webhook. Future send_email calls to that address return SuppressedAddressError before the request reaches the queue — no explicit suppression call is required from your agent.
Can I remove an address from the suppression list?
Yes, via DELETE /v1/suppression/{address}. This is appropriate when a contact updates their email address or explicitly confirms their mailbox is active. Removal is a manual operation — MultiMail does not auto-unsuppress, because the original hard bounce signal remains valid until the contact provides evidence of a working address.
Does Yellow domain status prevent sends?
No. Yellow domains are flagged in the API response with the domain_risk field set to yellow and a domain_signals array identifying the specific concern. The send proceeds unless your agent explicitly handles the yellow case and aborts. MultiMail surfaces the signal; your agent makes the decision.
How does platform-wide bounce data work without exposing other tenants' data?
MultiMail aggregates bounce signals into a shared domain reputation model that is separate from per-tenant contact data. Your agent sees a domain classified as Red or Yellow based on aggregate signals — it does not see which other tenants sent to that domain or what their results were. Your contact list and suppression list are strictly tenant-scoped.

Explore more use cases

The only agent email with a verifiable sender

Email infrastructure built for AI agents. Verifiable identity, graduated oversight, and a 50-tool MCP server. Formally verified in Lean 4.