{"id":"000f41d9-aa9b-4997-a3c7-ec36af812a7a","shortId":"jsAcQ9","kind":"skill","title":"agent-email-inbox","tagline":"Use when setting up a secure email inbox for any AI agent — configuring inbound email via Resend, webhooks, tunneling for local development, and implementing security measures to prevent prompt injection attacks. Also use when someone mentions 'agent email', 'bot inbox', 'receive","description":"# AI Agent Email Inbox\n\nSet up a secure email inbox that lets an AI agent receive and respond to emails, with protection against prompt injection and email-based attacks.\n\n**Core principle:** An AI agent's inbox is a potential attack vector. Malicious actors can email instructions that the agent might blindly follow. Security configuration is not optional — it's the first thing you implement, not the last.\n\nThis skill is context-independent — it does not use `brand/` files and works identically in any project.\n\n## On Activation\n\n1. Ask the user which agent needs an email inbox and what framework they're using (Next.js, Express, etc.).\n2. Determine environment: local development or production deployment.\n3. Walk through domain setup (Resend-managed or custom).\n4. Set up webhook endpoint with signature verification.\n5. If local dev: configure tunneling.\n6. Implement security level — read [references/security-levels.md](references/security-levels.md) and present options to the user.\n7. Connect webhook to agent processing.\n\n**Output:** A configured webhook handler file, environment variable checklist, and security configuration.\n\n## Architecture\n\n```\nSender → Email → Resend (MX) → Webhook → Your Server → AI Agent\n                                              ↓\n                                    Security Validation\n                                              ↓\n                                    Process or Reject\n```\n\n## Before You Start: Account & API Key Setup\n\nAsk the user:\n- **New account just for the agent?** → Simpler setup, full account access is fine\n- **Existing account with other projects?** → Use domain-scoped API keys to limit what the agent can access. Even if the key leaks, it can only send from one domain.\n\n> **Don't paste API keys in chat!** They'll persist in conversation history. Have the user write directly to `.env` or use a secrets manager.\n\n## Domain Setup\n\n### Option 1: Resend-Managed Domain (Recommended for Getting Started)\n\nUse your auto-generated address: `<anything>@<your-id>.resend.app`. No DNS configuration needed.\n\n### Option 2: Custom Domain\n\nThe user enables receiving in the Resend dashboard, then adds an MX record:\n\n| Setting | Value |\n|---------|-------|\n| **Type** | MX |\n| **Host** | Your domain or subdomain (e.g., `agent.yourdomain.com`) |\n| **Value** | Provided in Resend dashboard |\n| **Priority** | 10 (lowest number takes precedence) |\n\n**Use a subdomain** (e.g., `agent.yourdomain.com`) to avoid disrupting existing email services on your root domain — otherwise all email routes to Resend.\n\n## Webhook Setup\n\nThe user registers a webhook in Resend dashboard (Webhooks → Add Webhook → select `email.received`). They need the endpoint URL you'll create and the signing secret for verification.\n\n```typescript\n// app/api/webhooks/email/route.ts (Next.js App Router)\nimport { Resend } from 'resend';\nimport { NextRequest, NextResponse } from 'next/server';\n\nconst resend = new Resend(process.env.RESEND_API_KEY);\n\nexport async function POST(req: NextRequest) {\n  try {\n    const payload = await req.text();\n\n    const event = resend.webhooks.verify({\n      payload,\n      headers: {\n        'svix-id': req.headers.get('svix-id'),\n        'svix-timestamp': req.headers.get('svix-timestamp'),\n        'svix-signature': req.headers.get('svix-signature'),\n      },\n      secret: process.env.RESEND_WEBHOOK_SECRET,\n    });\n\n    if (event.type === 'email.received') {\n      const { data: email } = await resend.emails.receiving.get(\n        event.data.email_id\n      );\n      // Security validation happens here (see Security Levels)\n      await processEmailForAgent(event.data, email);\n    }\n\n    return new NextResponse('OK', { status: 200 });\n  } catch (error) {\n    console.error('Webhook error:', error);\n    return new NextResponse('Error', { status: 400 });\n  }\n}\n```\n\nResend retries failed deliveries with exponential backoff over ~6 hours. Emails are stored even if webhooks fail.\n\n## Local Development with Tunneling\n\nYour local server isn't accessible from the internet. Use tunneling to expose it:\n\n| Option | Persistent URL? | Cost |\n|--------|----------------|------|\n| **ngrok (paid)** | Yes (static subdomain) | $8/mo |\n| **Cloudflare named tunnel** | Yes (your own domain) | Free |\n| **ngrok (free)** | No (changes on restart) | Free |\n| **VS Code Port Forwarding** | No (changes per session) | Free |\n\nFor webhooks, persistent URLs matter — otherwise you re-register the URL every time the tunnel restarts. See the tunneling docs for each tool for setup instructions.\n\n```bash\n# ngrok (paid - recommended for persistent dev)\nngrok http --domain=myagent.ngrok.io 3000\n\n# Cloudflare named tunnel (free but more setup)\ncloudflared tunnel run my-agent-webhook\n```\n\n## Production Deployment\n\nFor a reliable agent inbox, deploy to production rather than relying on tunnels:\n\n- **Serverless** (Vercel, Netlify, Cloudflare Workers) — zero server management, automatic HTTPS\n- **VPS/cloud** — webhook handler runs alongside your agent, use nginx/caddy for HTTPS\n- **Existing infrastructure** — add webhook route to your agent's existing web server\n\n## Security Levels\n\nThis is the most critical part of the setup. An AI agent that processes emails without security is dangerous.\n\nThere are 5 graduated security levels. Read [references/security-levels.md](references/security-levels.md) for complete code examples and implementation details. Present the options to the user and help them choose:\n\n| Level | Approach | Best For |\n|-------|----------|----------|\n| **1. Strict Allowlist** | Only process emails from approved addresses | Personal assistant agents |\n| **2. Domain Allowlist** | Allow any address at approved domains | Team/org internal agents |\n| **3. Content Filtering** | Accept from anyone, filter injection patterns | Customer support agents |\n| **4. Sandboxed Processing** | Accept all, restrict agent capabilities | Public-facing agents |\n| **5. Human-in-the-Loop** | Require human approval for untrusted senders | High-stakes agents |\n\nLevels can be combined (e.g., Domain Allowlist + Content Filtering).\n\n### Security Best Practices\n\n| Practice | Why |\n|----------|-----|\n| Verify webhook signatures | Spoofed events let attackers control your agent |\n| Log all rejected emails | Audit trail reveals attack patterns |\n| Use allowlists where possible | Explicit trust is safer than trying to filter bad input |\n| Rate limit email processing | A flood of emails can overwhelm your agent or exhaust API quotas |\n| Separate trusted/untrusted handling | Different risk levels need different agent capabilities |\n\n### What to Avoid\n\n| Anti-Pattern | Risk |\n|--------------|------|\n| Processing emails without validation | Anyone can control your agent by sending an email |\n| Trusting email headers for authentication | \"From:\" headers are trivially spoofed — use webhook verification instead |\n| Executing code from email content | Remote code execution — the most dangerous vulnerability |\n| Storing email content in prompts verbatim | Prompt injection attacks bypass your security layer entirely |\n| Giving untrusted emails full agent access | One malicious email could compromise your entire system |\n\n## Agent Integration\n\nConnect your webhook to your AI agent:\n\n```typescript\nasync function processWithAgent(email: ProcessedEmail) {\n  const message = `New Email\\nFrom: ${email.from}\\nSubject: ${email.subject}\\n\\n${email.body}`.trim();\n  await sendToAgent(message);\n}\n```\n\nAlternatively, the agent can poll the Resend API during heartbeats instead of using webhooks — simpler architecture but less immediate.\n\n## Complete Example\n\nSee [references/security-levels.md](references/security-levels.md) for the complete secure agent inbox implementation with configurable security levels, rate limiting, content truncation, and rejection logging.\n\n## Environment Variables\n\n```bash\nRESEND_API_KEY=re_xxxxxxxxx\nRESEND_WEBHOOK_SECRET=whsec_xxxxxxxxx\nSECURITY_LEVEL=strict                    # strict | domain | filtered | sandboxed\nALLOWED_SENDERS=you@example.com,trusted@example.com\nALLOWED_DOMAINS=yourcompany.com\nOWNER_EMAIL=you@example.com             # For security notifications\n```\n\n## Common Mistakes\n\n| Mistake | Why It's a Problem | Fix |\n|---------|-------------------|-----|\n| No sender verification | Anyone can control your agent | Implement a security level (start with Level 1) |\n| Trusting email headers | Headers are trivially spoofed | Rely on webhook signature verification only |\n| Same treatment for all emails | Trusted and untrusted senders have different risk profiles | Use capability-based access control |\n| Using ephemeral tunnel URLs | URL changes on restart, breaking webhook delivery | Use paid ngrok or Cloudflare named tunnels |\n| No rate limiting | Flooding attacks can overwhelm the agent | Implement per-sender rate limits |\n| Processing HTML directly | HTML can contain hidden injection content | Strip to plain text before processing |\n\n## Testing\n\n- `delivered@resend.dev` — simulates successful delivery\n- `bounced@resend.dev` — simulates hard bounce\n- Send from non-allowlisted addresses to verify rejection works\n\n## Related Skills\n\n- `send-email` — sending emails from your agent\n- `resend-inbound` — detailed inbound email processing (domain setup, content retrieval, attachments)","tags":["agent","email","inbox","marketing","cli","moizibnyousaf","agent-skills","ai-agents","ai-marketing","brand-memory","brand-voice","claude-code"],"capabilities":["skill","source-moizibnyousaf","skill-agent-email-inbox","topic-agent-skills","topic-ai-agents","topic-ai-marketing","topic-brand-memory","topic-brand-voice","topic-claude-code","topic-claude-code-skills","topic-cli","topic-cmo","topic-marketing-automation","topic-marketing-cli","topic-seo"],"categories":["marketing-cli"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/MoizIbnYousaf/marketing-cli/agent-email-inbox","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add MoizIbnYousaf/marketing-cli","source_repo":"https://github.com/MoizIbnYousaf/marketing-cli","install_from":"skills.sh"}},"qualityScore":"0.459","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 18 github stars · SKILL.md body (9,318 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:05:47.392Z","embedding":null,"createdAt":"2026-05-04T19:06:11.336Z","updatedAt":"2026-05-18T19:05:47.392Z","lastSeenAt":"2026-05-18T19:05:47.392Z","tsv":"'1':134,312,743,1083 '10':366 '2':153,333,755 '200':509 '3':161,767 '3000':629 '4':171,779 '400':521 '5':179,715,791 '6':185,530 '7':198 '8/mo':566 'accept':770,782 'access':251,271,548,945,1114 'account':234,242,250,255 'activ':133 'actor':89 'add':345,403,682 'address':326,751,760,1178 'agent':2,16,41,47,60,80,95,139,202,225,246,269,642,649,675,687,705,754,766,778,785,790,806,830,865,878,895,944,954,962,986,1012,1075,1142,1192 'agent-email-inbox':1 'agent.yourdomain.com':359,375 'ai':15,46,59,79,224,704,961 'allow':758,1046,1050 'allowlist':745,757,813,841,1177 'alongsid':673 'also':36 'altern':984 'anti':884 'anti-pattern':883 'anyon':772,891,1071 'api':235,263,287,440,868,991,1030 'app':424 'app/api/webhooks/email/route.ts':422 'approach':740 'approv':750,762,799 'architectur':216,999 'ask':135,238 'assist':753 'async':443,964 'attach':1204 'attack':35,75,86,827,838,934,1138 'audit':835 'authent':904 'auto':324 'auto-gener':323 'automat':667 'avoid':377,882 'await':451,489,500,981 'backoff':528 'bad':852 'base':74,1113 'bash':618,1028 'best':741,817 'blind':97 'bot':43 'bounc':1172 'bounced@resend.dev':1169 'brand':124 'break':1124 'bypass':935 'capability-bas':1111 'capabl':786,879,1112 'catch':510 'chang':578,587,1121 'chat':290 'checklist':212 'choos':738 'cloudflar':567,630,637,662,1131 'code':583,724,915,920 'combin':810 'common':1059 'complet':723,1003,1010 'compromis':950 'configur':17,100,183,206,215,330,1016 'connect':199,956 'console.error':512 'const':435,449,453,486,969 'contain':1154 'content':768,814,918,928,1021,1157,1202 'context':118 'context-independ':117 'control':828,893,1073,1115 'convers':295 'core':76 'cost':560 'could':949 'creat':414 'critic':698 'custom':170,334,776 'danger':712,924 'dashboard':343,364,401 'data':487 'delivered@resend.dev':1165 'deliveri':525,1126,1168 'deploy':160,645,651 'detail':728,1196 'determin':154 'dev':182,624 'develop':26,157,540 'differ':873,877,1107 'direct':301,1151 'disrupt':378 'dns':329 'doc':611 'domain':164,261,283,309,316,335,355,385,573,627,756,763,812,1043,1051,1200 'domain-scop':260 'e.g':358,374,811 'email':3,11,19,42,48,54,65,73,91,142,218,380,388,488,503,532,708,748,834,856,861,888,899,901,917,927,942,948,967,972,1054,1085,1101,1187,1189,1198 'email-bas':72 'email.body':979 'email.from':974 'email.received':406,485 'email.subject':976 'enabl':338 'endpoint':175,410 'entir':939,952 'env':303 'environ':155,210,1026 'ephemer':1117 'error':511,514,515,519 'etc':152 'even':272,535 'event':454,825 'event.data':502 'event.data.email':491 'event.type':484 'everi':603 'exampl':725,1004 'execut':914,921 'exhaust':867 'exist':254,379,680,689 'explicit':844 'exponenti':527 'export':442 'expos':555 'express':151 'face':789 'fail':524,538 'file':125,209 'filter':769,773,815,851,1044 'fine':253 'first':107 'fix':1067 'flood':859,1137 'follow':98 'forward':585 'framework':146 'free':574,576,581,590,633 'full':249,943 'function':444,965 'generat':325 'get':319 'give':940 'graduat':716 'handl':872 'handler':208,671 'happen':495 'hard':1171 'header':457,902,906,1086,1087 'heartbeat':993 'help':736 'hidden':1155 'high':804 'high-stak':803 'histori':296 'host':353 'hour':531 'html':1150,1152 'http':626 'https':668,679 'human':793,798 'human-in-the-loop':792 'id':460,464,492 'ident':128 'immedi':1002 'implement':28,110,186,727,1014,1076,1143 'import':426,430 'inbound':18,1195,1197 'inbox':4,12,44,49,55,82,143,650,1013 'independ':119 'infrastructur':681 'inject':34,70,774,933,1156 'input':853 'instead':913,994 'instruct':92,617 'integr':955 'intern':765 'internet':551 'isn':546 'key':236,264,275,288,441,1031 'last':113 'layer':938 'leak':276 'less':1001 'let':57,826 'level':188,499,693,718,739,807,875,1018,1040,1079,1082 'limit':266,855,1020,1136,1148 'll':292,413 'local':25,156,181,539,544 'log':831,1025 'loop':796 'lowest':367 'malici':88,947 'manag':168,308,315,666 'matter':595 'measur':30 'mention':40 'messag':970,983 'might':96 'mistak':1060,1061 'mx':220,347,352 'my-agent-webhook':640 'myagent.ngrok.io':628 'n':977,978 'name':568,631,1132 'need':140,331,408,876 'netlifi':661 'new':241,437,505,517,971 'next.js':150,423 'next/server':434 'nextrequest':431,447 'nextrespons':432,506,518 'nfrom':973 'nginx/caddy':677 'ngrok':561,575,619,625,1129 'non':1176 'non-allowlist':1175 'notif':1058 'nsubject':975 'number':368 'ok':507 'one':282,946 'option':103,194,311,332,557,731 'otherwis':386,596 'output':204 'overwhelm':863,1140 'owner':1053 'paid':562,620,1128 'part':699 'past':286 'pattern':775,839,885 'payload':450,456 'per':588,1145 'per-send':1144 'persist':293,558,593,623 'person':752 'plain':1160 'poll':988 'port':584 'possibl':843 'post':445 'potenti':85 'practic':818,819 'preced':370 'present':193,729 'prevent':32 'principl':77 'prioriti':365 'problem':1066 'process':203,228,707,747,781,857,887,1149,1163,1199 'process.env.resend':439,480 'processedemail':968 'processemailforag':501 'processwithag':966 'product':159,644,653 'profil':1109 'project':131,258 'prompt':33,69,930,932 'protect':67 'provid':361 'public':788 'public-fac':787 'quota':869 'rate':854,1019,1135,1147 'rather':654 're':148,599,1032 're-regist':598 'read':189,719 'receiv':45,61,339 'recommend':317,621 'record':348 'references/security-levels.md':190,191,720,721,1006,1007 'regist':396,600 'reject':230,833,1024,1181 'relat':1183 'reli':656,1091 'reliabl':648 'remot':919 'req':446 'req.headers.get':461,468,475 'req.text':452 'requir':797 'resend':21,167,219,314,342,363,391,400,427,429,436,438,522,990,1029,1034,1194 'resend-inbound':1193 'resend-manag':166,313 'resend.app':327 'resend.emails.receiving.get':490 'resend.webhooks.verify':455 'respond':63 'restart':580,607,1123 'restrict':784 'retri':523 'retriev':1203 'return':504,516 'reveal':837 'risk':874,886,1108 'root':384 'rout':389,684 'router':425 'run':639,672 'safer':847 'sandbox':780,1045 'scope':262 'secret':307,418,479,482,1036 'secur':10,29,53,99,187,214,226,493,498,692,710,717,816,937,1011,1017,1039,1057,1078 'see':497,608,1005 'select':405 'send':280,897,1173,1186,1188 'send-email':1185 'sender':217,802,1047,1069,1105,1146 'sendtoag':982 'separ':870 'server':223,545,665,691 'serverless':659 'servic':381 'session':589 'set':7,50,172,349 'setup':165,237,248,310,393,616,636,702,1201 'sign':417 'signatur':177,474,478,823,1094 'simpler':247,998 'simul':1166,1170 'skill':115,1184 'skill-agent-email-inbox' 'someon':39 'source-moizibnyousaf' 'spoof':824,909,1090 'stake':805 'start':233,320,1080 'static':564 'status':508,520 'store':534,926 'strict':744,1041,1042 'strip':1158 'subdomain':357,373,565 'success':1167 'support':777 'svix':459,463,466,470,473,477 'svix-id':458,462 'svix-signatur':472,476 'svix-timestamp':465,469 'system':953 'take':369 'team/org':764 'test':1164 'text':1161 'thing':108 'time':604 'timestamp':467,471 'tool':614 'topic-agent-skills' 'topic-ai-agents' 'topic-ai-marketing' 'topic-brand-memory' 'topic-brand-voice' 'topic-claude-code' 'topic-claude-code-skills' 'topic-cli' 'topic-cmo' 'topic-marketing-automation' 'topic-marketing-cli' 'topic-seo' 'trail':836 'treatment':1098 'tri':448,849 'trim':980 'trivial':908,1089 'truncat':1022 'trust':845,900,1084,1102 'trusted/untrusted':871 'trusted@example.com':1049 'tunnel':23,184,542,553,569,606,610,632,638,658,1118,1133 'type':351 'typescript':421,963 'untrust':801,941,1104 'url':411,559,594,602,1119,1120 'use':5,37,123,149,259,305,321,371,552,676,840,910,996,1110,1116,1127 'user':137,197,240,299,337,395,734 'valid':227,494,890 'valu':350,360 'variabl':211,1027 'vector':87 'verbatim':931 'vercel':660 'verif':178,420,912,1070,1095 'verifi':821,1180 'via':20 'vps/cloud':669 'vs':582 'vulner':925 'walk':162 'web':690 'webhook':22,174,200,207,221,392,398,402,404,481,513,537,592,643,670,683,822,911,958,997,1035,1093,1125 'whsec':1037 'without':709,889 'work':127,1182 'worker':663 'write':300 'xxxxxxxxx':1033,1038 'yes':563,570 'you@example.com':1048,1055 'yourcompany.com':1052 'zero':664","prices":[{"id":"e51c1bc7-e1ed-47e9-89c7-ebf351a100b8","listingId":"000f41d9-aa9b-4997-a3c7-ec36af812a7a","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"MoizIbnYousaf","category":"marketing-cli","install_from":"skills.sh"},"createdAt":"2026-05-04T19:06:11.336Z"}],"sources":[{"listingId":"000f41d9-aa9b-4997-a3c7-ec36af812a7a","source":"github","sourceId":"MoizIbnYousaf/marketing-cli/agent-email-inbox","sourceUrl":"https://github.com/MoizIbnYousaf/marketing-cli/tree/main/skills/agent-email-inbox","isPrimary":false,"firstSeenAt":"2026-05-04T19:06:11.336Z","lastSeenAt":"2026-05-18T19:05:47.392Z"}],"details":{"listingId":"000f41d9-aa9b-4997-a3c7-ec36af812a7a","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"MoizIbnYousaf","slug":"agent-email-inbox","github":{"repo":"MoizIbnYousaf/marketing-cli","stars":18,"topics":["agent-skills","ai-agents","ai-marketing","brand-memory","brand-voice","claude-code","claude-code-skills","cli","cmo","marketing-automation","marketing-cli","seo","skills-sh","typescript"],"license":"mit","html_url":"https://github.com/MoizIbnYousaf/marketing-cli","pushed_at":"2026-05-13T21:06:05Z","description":"Agent-native marketing cli: 51 skills, 5 research agents, brand memory that compounds, plus a local Studio dashboard (beta). single agent-native cli, then /cmo in ur coding agent..","skill_md_sha":"73e6dd1e47a86c25288c21ed4c2f4338c87714bc","skill_md_path":"skills/agent-email-inbox/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/MoizIbnYousaf/marketing-cli/tree/main/skills/agent-email-inbox"},"layout":"multi","source":"github","category":"marketing-cli","frontmatter":{"name":"agent-email-inbox","description":"Use when setting up a secure email inbox for any AI agent — configuring inbound email via Resend, webhooks, tunneling for local development, and implementing security measures to prevent prompt injection attacks. Also use when someone mentions 'agent email', 'bot inbox', 'receive emails for agent', 'agent webhook', 'email security for AI', 'prompt injection via email', 'inbound email for bot', or wants their AI agent to receive and respond to emails securely."},"skills_sh_url":"https://skills.sh/MoizIbnYousaf/marketing-cli/agent-email-inbox"},"updatedAt":"2026-05-18T19:05:47.392Z"}}