The Policy Rules That Protect Your Sender Reputation

2026-03-20

Your agent calls request-send. Between that moment and the email actually leaving the wire, a lot happens. The policy engine evaluates the request against every rule in your mailbox's policy profile, in sequence. Any single failure blocks the send and returns a structured rejection the agent can act on.

This post walks through every rule, what it catches, and why it matters. If you've read our earlier post on what happens when an agent over-sends, think of this as the other side of that story: the infrastructure that prevents it.

How the policy cascade works

When a send request arrives, the engine doesn't just check one thing. It runs the full cascade, rule by rule, and stops at the first failure. The response always includes the rule that blocked it and enough context for the agent to decide what to do next (wait, skip, escalate, try a different recipient).

{
  "requestId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "blocked",
  "reason": "cooldown",
  "detail": "Recipient was contacted 2 hours ago",
  "cooldownExpiresAt": "2026-03-20T14:45:00Z"
}

No ambiguity. No soft failure the agent might read as "try harder." A clear reason, a clear next step.

Here's what the cascade checks.

Account and template gates

These fire first because there's no point evaluating recipient-level rules if the account or template itself isn't ready to send.

Tenant paused. If your account is suspended or paused (billing issue, manual hold, abuse flag), every send is blocked immediately. This is the kill switch.

Template not approved. Templates that haven't been reviewed and approved can't be used for sending. This catches the case where an agent references a draft template that someone hasn't signed off on yet. For teams that want tight control over what their agents say, this is the gate.

Template lint failures. Even approved templates get linted on every send. The linter checks five things: spam-trigger phrases ("act now," "limited time," "free money" and about a dozen others that inbox providers flag), undeclared variables that would render as blank or broken placeholders, unused variables that suggest a copy-paste error, insecure HTTP URLs in a world that expects HTTPS, and missing unsubscribe links in marketing templates. That last one is a CAN-SPAM requirement, not a suggestion.

Recipient-level checks

Once the template passes, the engine looks at the specific recipient.

Suppression. The engine checks the recipient against your suppression lists before anything else. There are seven reasons a recipient can be suppressed: hard bounce (the address doesn't exist), complaint (they reported you as spam), manual do-not-contact (someone on your team flagged them), legal request, role account (like info@ or noreply@), domain-level suppression (the entire domain is blocked), and no engagement (they've received multiple emails and never opened one).

Sending to a suppressed address is the fastest way to damage your reputation. Every hard bounce tells the receiving server you don't maintain your lists. Every complaint tells it your recipients don't want your email. The suppression check is arguably the single most important rule in the cascade.

Disengaged recipients. Separate from suppression, this catches recipients who technically haven't bounced or complained but show clear signs of disengagement. The fatigue calculator scores each contact based on send frequency, monthly volume, bounce history, complaint history, and engagement decay. A contact with a fatigue score above 70 gets blocked with a stop_sending recommendation. Between 40 and 70, the agent gets a reduce_frequency signal.

This is subtler than suppression. A recipient might be valid and never complained, but if you've sent them 12 emails in the last month and they haven't opened one, continuing to send is just running up your complaint risk.

Active opportunity. If the recipient has an active deal in a sales-sensitive stage (demo scheduled, proposal out, negotiation, contract sent), the policy engine blocks automated sends. The last thing you want is an AI agent sending a generic nurture email to someone your sales team is closing this week. This rule exists because we heard from teams where exactly that happened.

Deduplication and frequency

Duplicate detection. The engine generates a dedupe key from the recipient, template, and content. If the same combination was sent recently, it blocks the retry. This is the rule that prevents the classic runaway loop: agent gets an ambiguous response, decides to "try again," and sends the same email five times in an hour.

Cooldown windows. Even if the content is different, the engine enforces per-recipient cooldown periods. You configure the window (default is 24 hours), and no agent can contact the same person twice within it, regardless of which template they use. The rejection includes the exact timestamp when the cooldown expires, so the agent can schedule a follow-up rather than just retrying immediately.

These two rules work together. Deduplication catches identical retries. Cooldowns catch the agent that drafts a "new" email to the same person an hour later.

Budget enforcement

This is where the engine protects you from volume problems, even when each individual send looks fine.

Daily send budget. A hard cap on sends per day for the tenant. When you hit it, sends are blocked until the next day. Straightforward.

Monthly send budget. Same idea, longer window. Paid plans allow overages up to 2x the monthly limit before the hard block kicks in. This gives you headroom for spikes without removing the ceiling entirely.

Risk budget. This one is more interesting. The risk budget tracks negative signals (bounces and complaints) as a ratio of total sends within a rolling window. If your bounce rate or complaint rate crosses the threshold, sending pauses automatically. You might be well within your volume limits but still get blocked because the quality of your sends is degrading.

Think of it this way: 50 sends a day is fine. 50 sends a day with a 15% bounce rate is a problem, and the risk budget catches it before your mailbox provider does.

Negative signal budget. Similar to the risk budget but focused on absolute counts rather than ratios. If you accumulate more than N bounces or complaints in a day, sends pause. This catches the scenario where a small number of sends to a bad list generates outsized damage.

Rate limiting

Triple-window rate limiting sits at the API layer as a separate check from the policy cascade's budget rules. Three separate windows: hourly, daily, and monthly. Each has an independent limit. The rate limiter enforces hard counter-based ceilings; the budget rules inside the cascade enforce spending context (plan allocation, risk ratios). They're complementary.

Why three? Because different problems show up at different time scales. An hourly limit catches retry loops and sudden bursts. A daily limit prevents sustained high-volume sends that look normal hour-by-hour but add up. A monthly limit enforces your plan's allocation.

A send that's within the hourly limit can still be blocked by the daily limit. The windows are independent, not nested.

Template content safety

Beyond the lint rules that run on every send, the template linter enforces content hygiene that protects your reputation and legal standing.

The spam phrase detector checks for the patterns that inbox providers actually flag: urgency phrases ("act now," "limited time," "urgent"), deceptive claims ("guaranteed," "no obligation," "free money"), and engagement bait ("congratulations," "winner"). Ten phrases in total, chosen because they're the ones most correlated with spam folder placement. If your agent drafts a subject line with "Act now" in it, the linter catches it before Gmail's spam filter does. Better to get a structured rejection from your own infrastructure than a silent trip to the spam folder.

The unsubscribe check is specific to marketing templates. Transactional emails (password resets, receipts, account notifications) are exempt. But anything classified as marketing must include an unsubscribe mechanism. CAN-SPAM has required this since 2003. GDPR reinforced it. Your agent doesn't need to know email law; the linter enforces it.

What the agent sees

Every blocked send returns the same structure: a status, the rule that triggered, a human-readable detail, and where relevant, a timestamp or threshold that tells the agent what changed. The agent can branch on the reason:

  • cooldown with an expiry? Schedule the send for later.
  • suppressed with reason hard_bounce? Remove the recipient from the sequence.
  • risk_budget_exceeded? Stop sending entirely and alert the operator.
  • template_lint_failed with detail spam_phrase? Rewrite the content.

This is the difference between a policy engine and a rate limiter. A rate limiter says "no." A policy engine says "no, because X, and here's what you can do about it."

Beyond the send path

The rules above cover outbound sends, but the policy engine extends into inbound processing too. When replies arrive, the engine runs safety classification (spam, phishing, malware, abuse, impersonation), prompt injection detection across four attack categories, intent classification, and thread integrity checks that catch forged replies and suspicious sender changes. Those are topics for their own posts.

The point is that the policy engine isn't just a gate on the send path. It's a continuous evaluation layer across the entire mailbox lifecycle.

The rules you don't see

The best policy enforcement is the kind you never think about. Your agent calls request-send, gets an approval, and the email goes out. It doesn't know that 12 rules passed before that approval happened. It doesn't know that the recipient was checked against suppression lists, the template was linted for spam phrases, the daily budget was verified, and the risk ratio was evaluated.

When a rule does fire, the agent gets a structured rejection it can act on. When all rules pass, the agent doesn't even know they ran. That's the goal: deterministic enforcement that's invisible when things are fine and actionable when they're not.


The policy engine is infrastructure, not configuration. It runs on every send, for every mailbox, with no way for the agent to bypass it. If you're building agents that send email and want to skip the part where you build all of this yourself, start a free trial or read the API docs.

Keep reading

Written by Magnus Junghard