惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hugging Face - Blog
Hugging Face - Blog
Recent Announcements
Recent Announcements
V
Visual Studio Blog
博客园 - 叶小钗
H
Help Net Security
aimingoo的专栏
aimingoo的专栏
宝玉的分享
宝玉的分享
U
Unit 42
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
F
Fortinet All Blogs
V
V2EX
Stack Overflow Blog
Stack Overflow Blog
WordPress大学
WordPress大学
D
DataBreaches.Net
J
Java Code Geeks
H
Hackread – Cybersecurity News, Data Breaches, AI and More
A
About on SuperTechFans
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
C
Check Point Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
小众软件
小众软件
Microsoft Azure Blog
Microsoft Azure Blog
M
MIT News - Artificial intelligence

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Filter what your AI email agent sends and receives
Qasim · 2026-06-23 · via DEV Community

An AI agent with its own mailbox reacts to whatever lands in it. That's the point, until a spam blast, a mailer-daemon loop, or an auto-reply triggers the agent into answering noise. The same goes the other way: an agent composing mail on its own can address the wrong person, leak to a test domain that slipped into production, or email a competitor because nobody told it not to. A human would catch these. An agent needs guardrails encoded somewhere it can't skip.

Agent Accounts ship three admin resources for exactly this: Policies bundle limits and spam settings, Rules match mail on the way in or out and run actions like block or assign_to_folder, and Lists are reusable collections of domains or addresses that rules reference. This post covers all three from two angles: the HTTP API for your backend, and the Nylas CLI for inspecting and managing policies and rules from the terminal. Lists, workspaces, and the rule-evaluations audit log are API-only for now. I work on the CLI, so the terminal commands below are the ones I reach for.

How Policies, Rules, and Lists fit together

The three resources form a chain, and a workspace ties it to your accounts. A List holds values like domains or addresses. A Rule references lists through the in_list operator and describes conditions and actions. A Policy bundles limits and spam settings. A workspace carries one policy_id plus an array of rule_ids, and every Agent Account in that workspace inherits both.

What matters here: you don't attach a policy or rule to an individual grant. You set policy_id and rule_ids on a workspace, and they apply to every account in it. Each application has a default workspace that holds any account you haven't placed elsewhere, so configuring that one workspace covers all your unassigned accounts at once. All three resources are application-scoped — they carry no grant ID in the path, and your API key identifies the application.

Resource What it owns How it's referenced
List A typed collection of domains, TLDs, or email addresses By ID, from a rule condition when operator is in_list
Rule A trigger (inbound or outbound), match conditions, and actions By ID, in a workspace's rule_ids array
Policy Limits and spam detection settings By ID, in a workspace's policy_id
Workspace The policy_id and rule_ids that govern its accounts By ID, in a grant's workspace_id

They're optional. Without a workspace policy, an account runs at your billing plan's maximum limits; without workspace rules, inbound mail is delivered to the inbox unfiltered. Reach for these only when you want stricter behavior or filtering.

Inspect what's already configured from the CLI

Before changing anything, see what exists. The Nylas CLI lists your policies and rules so you can audit the current setup without opening the Dashboard. This is usually my first step when I pick up an application I didn't configure myself.

# List policies and rules on the application
nylas agent policy list
nylas agent rule list

# Fetch a single policy or rule by ID
nylas agent policy get <policy-id>
nylas agent rule get <rule-id>

The same listing is available over the API at GET /v3/policies and GET /v3/rules. Both surfaces return the application's resources, since policies and rules aren't grant-scoped. Once you know what's there, you can create new ones or update the workspace assignments.

Set limits and spam detection with a Policy

A policy is the configuration you reuse across many accounts. It holds a limits object — attachment size and count, allowed MIME types, total message size, per-account storage, daily send quota, and inbox and spam retention — and a spam_detection object with DNSBL checking, header anomaly detection, and a spam_sensitivity dial from 0.1 to 5.0 where higher is more aggressive. Every limit is optional and defaults to your plan's maximum; requesting a value above the plan maximum returns an error.

These are the limit fields you set most often, each enforced per Agent Account:

Field What it controls
limit_count_daily_message_received Messages the account can receive per day
limit_attachment_size_limit Size of a single inbound attachment, in bytes
limit_attachment_count_limit Attachments allowed on one inbound message
limit_count_daily_email_sent Messages the account can send per day
limit_storage_total Total stored bytes per account
limit_inbox_retention_period Days a message stays in the inbox before deletion
limit_spam_retention_period Days a message stays in spam before deletion

Create a policy over the API with POST /v3/policies. The body below caps attachments at 25 MB, keeps inbox mail for a year and spam for 30 days, and turns spam detection up slightly to a sensitivity of 1.5:

curl --request POST \
  --url "https://api.us.nylas.com/v3/policies" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "Standard Agent Account Policy",
    "limits": {
      "limit_attachment_size_limit": 26214400,
      "limit_inbox_retention_period": 365,
      "limit_spam_retention_period": 30
    },
    "spam_detection": {
      "use_list_dnsbl": true,
      "use_header_anomaly_detection": true,
      "spam_sensitivity": 1.5
    }
  }'

The CLI creates the same policy from the terminal. nylas agent policy create takes a --name and the configuration as inline JSON with --data, or from a file with --data-file — handy for keeping policy definitions in version control:

nylas agent policy create \
  --name "Standard Agent Account Policy" \
  --data-file ./standard-policy.json

A policy does nothing until a workspace references it. Attach it by setting policy_id on a workspace with PATCH /v3/workspaces/{workspace_id}, and every account in that workspace picks up its limits and spam settings. Set the spam retention shorter than the inbox retention, since spam should clear out ahead of real mail.

Block inbound spam before the agent sees it

A rule decides what to do with a message, either on the way in or on the way out. An inbound rule matches on sender fields and runs actions when it hits. The most useful one for an agent is block: it rejects the message at the SMTP layer, so the message never lands in the mailbox and your application never sees it. Inbound rules can match from.address, from.domain, and from.tld with the operators is, is_not, contains, and in_list.

This rule blocks every message from a known bad domain. Rules run in priority order from 0 to 1000, lowest first, defaulting to 10, and a block action is terminal — it can't be combined with other actions:

curl --request POST \
  --url "https://api.us.nylas.com/v3/rules" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "Block spam-domain.com",
    "priority": 1,
    "trigger": "inbound",
    "match": {
      "conditions": [
        { "field": "from.domain", "operator": "is", "value": "spam-domain.com" }
      ]
    },
    "actions": [{ "type": "block" }]
  }'

From the CLI, nylas agent rule create builds the same rule. You can pass the whole definition with --data-file, or assemble it inline with --trigger, --condition, and --action flags:

nylas agent rule create \
  --name "Block spam-domain.com" \
  --data-file ./block-rule.json

Block isn't the only action. To route instead of reject, pair assign_to_folder with mark_as_read to move newsletters into a reading folder and mark them read in one rule. The full action set is block, mark_as_spam, assign_to_folder, mark_as_read, mark_as_starred, archive, and trash. A rule only runs once a workspace lists its ID in rule_ids; one array carries both inbound and outbound rules, and Nylas filters by trigger at evaluation time.

Stop sends to the wrong recipients with outbound rules

Outbound rules are where an agent gets data-loss prevention. They run when the account issues a send, before the message reaches the email provider, so a block action short-circuits delivery entirely — the API returns 403 and no sent copy is stored. Outbound rules can match from.*, plus recipient.address, recipient.domain, recipient.tld, and outbound.type.

The recipient.* fields match against any recipient, including BCC and SMTP envelope recipients, which is what makes them useful for DLP — a hidden BCC to a blocked domain still trips the rule. This one blocks any send to a specific domain, the kind of hard stop you'd use for a competitor or a test domain:

curl --request POST \
  --url "https://api.us.nylas.com/v3/rules" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{
    "name": "Block outbound to example.net",
    "trigger": "outbound",
    "match": {
      "conditions": [
        { "field": "recipient.domain", "operator": "is", "value": "example.net" }
      ]
    },
    "actions": [{ "type": "block" }]
  }'

The outbound.type field narrows a rule to replies or brand-new messages without looking at recipients at all. It takes two values: reply when the send includes reply_to_message_id or the raw MIME carries In-Reply-To or References, and compose for everything else. It supports only is and is_not. A rule with outbound.type is reply lets you, say, auto-star every reply the agent sends. Non-blocking outbound actions like archive and mark_as_starred apply to the stored sent copy after the send succeeds — they don't change what the recipient receives.

One behavior worth designing for: rule evaluation fails closed. If a block rule can't be evaluated because of a transient error, like a list lookup failing during in_list matching, Nylas blocks rather than letting the message through. Inbound, that surfaces as a 451 tempfail so the sending server retries; on an API send it returns 503 instead of 403, so your application can retry too.

Maintain dynamic allow and block lists

When the set of blocked domains changes over time, you don't want to edit rules every time. A List is a typed collection of values a rule matches against through in_list, so you update the list and every rule referencing it picks up the change immediately. Each list has a fixed type set at creation: domain for domain names, tld for top-level domains, or address for full email addresses.

Lists have no CLI command, so you manage them over the API. Create a list, then add up to 1000 items per request. Values are lowercased and trimmed on write and validated against the list's type, so a domain list rejects full email addresses:

# Create the list
curl --request POST \
  --url "https://api.us.nylas.com/v3/lists" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{ "name": "Blocked domains", "type": "domain" }'

# Add items to it
curl --request POST \
  --url "https://api.us.nylas.com/v3/lists/<LIST_ID>/items" \
  --header "Authorization: Bearer <NYLAS_API_KEY>" \
  --header "Content-Type: application/json" \
  --data '{ "items": ["spam-domain.com", "another-bad-domain.net"] }'

To use the list, set a rule condition's operator to in_list and pass one or more list IDs as the value. A single in_list condition can reference up to 10 lists. Rules cap at 50 conditions and 20 actions each, with up to 500 characters per condition value, so a list is the right tool once a block set grows past a handful of inline values. Lists let a non-engineer update who's allowed or blocked without touching rule definitions or redeploying anything.

Audit which rules ran

When a message gets blocked, routed, or marked and you need to know why, the rule-evaluations endpoint is the fastest answer. Every time the engine evaluates an inbound message, an SMTP envelope, or an outbound send for an account, Nylas records an audit entry. List them, most recent first, with GET /v3/grants/{grant_id}/rule-evaluations:

curl --request GET \
  --url "https://api.us.nylas.com/v3/grants/<GRANT_ID>/rule-evaluations?limit=50" \
  --header "Authorization: Bearer <NYLAS_API_KEY>"

Each record names the evaluation stage — smtp_rcpt when a message was rejected before acceptance, inbox_processing after acceptance, or outbound_send at send time — the normalized sender and recipient data considered, the IDs of any matched rules, and the actions applied. When a block came from a fail-closed evaluation error rather than a genuine match, the record carries blocked_by_evaluation_error: true, so you can tell an infrastructure hiccup apart from a real rule hit. Cross-reference matched_rule_ids with nylas agent rule get to see the conditions behind each match.

Things to keep in mind

A few practices keep this system predictable as it grows. None are complicated, but each one prevents a class of surprise.

  • Order rules by specificity. Lower priority runs first and the first block is terminal, so put narrow rules (is, in_list against a small list) ahead of broad ones (contains).
  • Pick the right trigger. Inbound rules only see received mail; outbound rules only see sends. They're isolated on purpose, so don't try to filter sends with an inbound rule.
  • Handle 403 from sends. An outbound block returns 403 with no sent copy stored. Treat it like any delivery failure — no retry path will deliver it.
  • Prefer lists over inline values when the set will grow. One list feeds many rules and updates without touching rule definitions.
  • Start spam sensitivity at 1.0 and tune from there: up if spam slips through, down if real mail gets marked.
  • Use separate workspaces per agent archetype. A sales-outreach agent and a support-triage agent have different send limits and spam tolerances — give each its own workspace and policy rather than one catch-all.

Wrapping up

Policies, Rules, and Lists give an agent the judgment it doesn't have on its own: what to drop on the way in, what to refuse on the way out, and how much it's allowed to send and store. The model is small once it clicks — lists feed rules, a policy bundles limits, and a workspace carries both to every account inside it. Build the pieces over the API or the CLI, attach them to a workspace, and the audit trail tells you exactly what fired.

Where to go next: