Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
resend avatar

Agent Email Inbox

  • 6.3k installs
  • 159 repo stars
  • Updated July 23, 2026
  • resend/resend-skills

agent-email-inbox is an agent skill for Use when building any system where email content triggers actions - AI agent inboxes, automated support handlers, emai

About

The agent-email-inbox skill use when building any system where email content triggers actions - AI agent inboxes, automated support handlers, email-to-task pipelines, or any workflow processing untrusted inbound email. Always use this skill when the user wants to receive emails and act on them programmatically, even if they don't mention "agent" - the skill contains critical security patterns (sender allowlists, content filtering, sandboxed processing) that prevent untrusted email from controlling your system.. AI Agent Email Inbox Overview This skill covers setting up a secure email inbox that allows your application or AI agent to receive and respond to emails, with content safety measures in place. Core principle: An AI agent's inbox receives untrusted input. Security configuration is important to handle this safely. Resend uses webhooks for inbound email, meaning your agent is notified instantly when an email arrives. This is valuable for agents because: - Real-time responsiveness - React to emails within seconds, not minutes - No polling overhead - No cron jobs checking "any new mail?" repeatedly - Event-driven

  • Use when building any system where email content triggers actions - AI agent inboxes, automated support handlers, emai
  • **Real-time responsiveness** - React to emails within seconds, not minutes
  • **No polling overhead** - No cron jobs checking "any new mail?" repeatedly
  • **Event-driven architecture** - Your agent only wakes up when there's actually something to process
  • **Lower API costs** - No wasted calls checking empty inboxes

Agent Email Inbox by the numbers

  • 6,277 all-time installs (skills.sh)
  • +471 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #106 of 2,203 Security skills by installs in the Skillselion catalog
  • Security screen: HIGH risk (skills.sh audit)
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
At a glance

agent-email-inbox capabilities & compatibility

Capabilities
use when building any system where email content · **real time responsiveness** react to emails w · **no polling overhead** no cron jobs checking
From the docs

What agent-email-inbox says it does

Don't paste API keys in chat! They'll be in conversation history forever.
SKILL.md
DNS Propagation: MX record changes can take up to 48 hours to propagate globally, though often complete within a few hours.
SKILL.md
**Critical: Use raw body for verification.** Webhook signature verification requires the raw request body.
SKILL.md
- **Next.js App Router:** Use `req.text()` (not `req.json()`)
SKILL.md
npx skills add https://github.com/resend/resend-skills --skill agent-email-inbox

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs6.3k
repo stars159
Security audit2 / 3 scanners passed
Last updatedJuly 23, 2026
Repositoryresend/resend-skills

How do I run agent-email-inbox tasks with correct setup and documented commands?

Use when building any system where email content triggers actions - AI agent inboxes, automated support handlers, email-to-task pipelines, or any workflow processing untrusted inbound email. Always

Who is it for?

Developers automating agent email inbox via agent-guided SKILL.md workflows.

Skip if: Skip when unrelated tooling already covers the task without this skill's documented flow.

When should I use this skill?

Use when building any system where email content triggers actions - AI agent inboxes, automated support handlers, email-to-task pipelines, or any workflow processing untrusted inbound email. Always

What you get

Repeatable agent-email-inbox workflows with grounded commands and expected outputs.

  • rate-limited inbox handler
  • sanitized message pipeline

By the numbers

  • Default per-sender rate limit of 10 emails per hour in the example

Files

SKILL.mdMarkdownGitHub ↗

AI Agent Email Inbox

Overview

This skill covers setting up a secure email inbox that allows your application or AI agent to receive and respond to emails, with content safety measures in place.

Core principle: An AI agent's inbox receives untrusted input. Security configuration is important to handle this safely.

Why Webhook-Based Receiving?

Resend uses webhooks for inbound email, meaning your agent is notified instantly when an email arrives. This is valuable for agents because:

  • Real-time responsiveness — React to emails within seconds, not minutes
  • No polling overhead — No cron jobs checking "any new mail?" repeatedly
  • Event-driven architecture — Your agent only wakes up when there's actually something to process
  • Lower API costs — No wasted calls checking empty inboxes

Architecture

Sender → Email → Resend (MX) → Webhook → Your Server → AI Agent
                                              ↓
                                    Security Validation
                                              ↓
                                    Process or Reject

SDK Version Requirements

This skill requires Resend SDK features for webhook verification (webhooks.verify()) and email receiving (emails.receiving.get()). Always install the latest SDK version. If the project already has a Resend SDK installed, check the version and upgrade if needed.

LanguagePackageMin Version
Node.jsresend>= 6.9.2
Pythonresend>= 2.21.0
Goresend-go/v3>= 3.1.0
Rubyresend>= 1.0.0
PHPresend/resend-php>= 1.1.0
Rustresend-rs>= 0.20.0
Javaresend-java>= 4.11.0
.NETResend>= 0.2.1

Install the resend npm package: npm install resend (or the equivalent for your language). For full sending docs, install the resend skill.

Quick Start

1. Ask the user for their email address — You need a real email address to send test emails to. Ask the user and wait for their response before proceeding. 2. Choose your security level — Decide how to validate incoming emails before any are processed 3. Set up receiving domain — Configure MX records for the user's custom domain (see Domain Setup section) 4. Create webhook endpoint — Handle email.received events with security built in from the start. The webhook endpoint MUST be a POST route. 5. Set up tunneling (local dev) — Use Tailscale Funnel (recommended) or ngrok. See references/webhook-setup.md 6. Create webhook via API — Use the Resend Webhook API to register your endpoint programmatically. See references/webhook-setup.md 7. Connect to agent — Pass validated emails to your AI agent for processing

Before You Start: Account & API Key Setup

First Question: New or Existing Resend Account?

Ask your human:

  • New account just for the agent? → Simpler setup, full account access is fine
  • Existing account with other projects? → Use domain-scoped API keys for sandboxing

Creating API Keys Securely

Don't paste API keys in chat! They'll be in conversation history forever.

Safer options:

1. Environment file method: Human creates .env file directly: echo "RESEND_API_KEY=re_xxx" >> .env 2. Password manager / secrets manager: Human stores key in 1Password, Vault, etc. 3. If key must be shared in chat: Human should rotate the key immediately after setup

Domain-Scoped API Keys (Recommended for Existing Accounts)

If your human has an existing Resend account with other projects, create a domain-scoped API key:

1. Verify the agent's domain first (Dashboard → Domains → Add Domain) 2. Create a scoped API key: Dashboard → API Keys → Create API Key → "Sending access" → select only the agent's domain 3. Result: Even if the key leaks, it can only send from one domain

Domain Setup

Option 1: Resend-Managed Domain (Recommended for Getting Started)

Use your auto-generated address: <anything>@<your-id>.resend.app

No DNS configuration needed. Find your address in Dashboard → Emails → Receiving → "Receiving address".

Option 2: Custom Domain

The user must enable receiving in the Resend dashboard: Domains page → toggle on "Enable Receiving".

Then add an MX record:

SettingValue
TypeMX
HostYour domain or subdomain (e.g., agent.example.com)
ValueProvided in Resend dashboard
Priority10 (must be lowest number to take precedence)

Use a subdomain (e.g., agent.example.com) to avoid disrupting existing email services.

Tip: Verify DNS propagation at dns.email.

DNS Propagation: MX record changes can take up to 48 hours to propagate globally, though often complete within a few hours.

Security Levels

Choose your security level before setting up the webhook endpoint. An AI agent that processes emails without security is dangerous — anyone can email instructions that your agent will execute. The webhook code you write next should include your chosen security level from the start.

Ask the user what level of security they want, and ensure that they understand what each level means.

LevelNameWhen to UseTrade-off
1Strict AllowlistMost use cases — known, fixed set of sendersMaximum security, limited functionality
2Domain AllowlistOrganization-wide access from trusted domainsMore flexible, anyone at domain can interact
3Content FilteringAccept from anyone, filter unsafe patternsCan receive from anyone, pattern matching not foolproof
4Sandboxed ProcessingProcess all emails with restricted agent capabilitiesMaximum flexibility, complex to implement
5Human-in-the-LoopRequire human approval for untrusted actionsMaximum security, adds latency

For detailed implementation code for each level, see references/security-levels.md.

Level 1: Strict Allowlist (Recommended)

Only process emails from explicitly approved addresses. Reject everything else.

const ALLOWED_SENDERS = [
  'you@youremail.com',
  'notifications@github.com',
];

async function processEmailForAgent(
  eventData: EmailReceivedEvent,
  emailContent: EmailContent
) {
  const sender = eventData.from.toLowerCase();

  if (!ALLOWED_SENDERS.some(allowed => sender === allowed.toLowerCase())) {
    console.log(`Rejected email from unauthorized sender: ${sender}`);
    await notifyOwnerOfRejectedEmail(eventData);
    return;
  }

  await agent.processEmail({
    from: eventData.from,
    subject: eventData.subject,
    body: emailContent.text || emailContent.html,
  });
}

Security Best Practices

Always Do
PracticeWhy
Verify webhook signaturesPrevents spoofed webhook events
Log all rejected emailsAudit trail for security review
Use allowlists where possibleExplicit trust is safer than filtering
Rate limit email processingPrevents excessive processing load
Separate trusted/untrusted handlingDifferent risk levels need different treatment
Never Do
Anti-PatternRisk
Process emails without validationAnyone can control your agent
Trust email headers for authenticationHeaders are trivially spoofed
Execute code from email contentUntrusted input should never run as code
Store email content in prompts verbatimUntrusted input mixed into prompts can alter agent behavior
Give untrusted emails full agent accessScope capabilities to the minimum needed

Webhook Endpoint

After choosing your security level and setting up your domain, create a webhook endpoint. The webhook endpoint MUST be a POST route. Resend sends all webhook events as POST requests.

Critical: Use raw body for verification. Webhook signature verification requires the raw request body.
- Next.js App Router: Use req.text() (not req.json())
- Express: Use express.raw({ type: 'application/json' }) on the webhook route

Next.js App Router

// app/webhook/route.ts
import { Resend } from 'resend';
import { NextRequest, NextResponse } from 'next/server';

const resend = new Resend(process.env.RESEND_API_KEY);

export async function POST(req: NextRequest) {
  try {
    const payload = await req.text();

    const event = resend.webhooks.verify({
      payload,
      headers: {
        'svix-id': req.headers.get('svix-id'),
        'svix-timestamp': req.headers.get('svix-timestamp'),
        'svix-signature': req.headers.get('svix-signature'),
      },
      secret: process.env.RESEND_WEBHOOK_SECRET,
    });

    if (event.type === 'email.received') {
      // Webhook payload only includes metadata, not email body
      const { data: email } = await resend.emails.receiving.get(
        event.data.email_id
      );

      // Apply the security level chosen above
      await processEmailForAgent(event.data, email);
    }

    return new NextResponse('OK', { status: 200 });
  } catch (error) {
    console.error('Webhook error:', error);
    return new NextResponse('Error', { status: 400 });
  }
}

Express

import express from 'express';
import { Resend } from 'resend';

const app = express();
const resend = new Resend(process.env.RESEND_API_KEY);

app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  try {
    const payload = req.body.toString();

    const event = resend.webhooks.verify({
      payload,
      headers: {
        'svix-id': req.headers['svix-id'],
        'svix-timestamp': req.headers['svix-timestamp'],
        'svix-signature': req.headers['svix-signature'],
      },
      secret: process.env.RESEND_WEBHOOK_SECRET,
    });

    if (event.type === 'email.received') {
      const sender = event.data.from.toLowerCase();

      if (!isAllowedSender(sender)) {
        console.log(`Rejected email from unauthorized sender: ${sender}`);
        res.status(200).send('OK'); // Return 200 even for rejected emails
        return;
      }

      const { data: email } = await resend.emails.receiving.get(event.data.email_id);
      await processEmailForAgent(event.data, email);
    }

    res.status(200).send('OK');
  } catch (error) {
    console.error('Webhook error:', error);
    res.status(400).send('Error');
  }
});

app.get('/', (req, res) => res.send('Agent Email Inbox - Ready'));
app.listen(3000, () => console.log('Webhook server running on :3000'));

For webhook registration via API, tunneling setup, svix fallback, and retry behavior, see references/webhook-setup.md.

Sending Emails from Your Agent

import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

async function sendAgentReply(to: string, subject: string, body: string, inReplyTo?: string) {
  if (!isAllowedToReply(to)) {
    throw new Error('Cannot send to this address');
  }

  const { data, error } = await resend.emails.send({
    from: 'Agent <agent@example.com>',
    to: [to],
    subject: subject.startsWith('Re:') ? subject : `Re: ${subject}`,
    text: body,
    headers: inReplyTo ? { 'In-Reply-To': inReplyTo } : undefined,
  });

  if (error) throw new Error(`Failed to send: ${error.message}`);
  return data.id;
}

For full sending docs, install the resend skill.

Environment Variables

# Required
RESEND_API_KEY=re_xxxxxxxxx
RESEND_WEBHOOK_SECRET=whsec_xxxxxxxxx

# Security Configuration
SECURITY_LEVEL=strict                    # strict | domain | filtered | sandboxed
ALLOWED_SENDERS=you@email.com,trusted@example.com
ALLOWED_DOMAINS=example.com
OWNER_EMAIL=you@email.com               # For security notifications

Common Mistakes

MistakeFix
No sender verificationAlways validate who sent the email before processing
Trusting email headersUse webhook verification, not email headers for auth
Same treatment for all emailsDifferentiate trusted vs untrusted senders
Verbose error messagesKeep error responses generic to avoid leaking internal logic
No rate limitingImplement per-sender rate limits. See references/advanced-patterns.md
Processing HTML directlyStrip HTML or use text-only to reduce complexity and risk
No logging of rejectionsLog all security events for audit
Using ephemeral tunnel URLsUse persistent URLs (Tailscale Funnel, paid ngrok) or deploy to production
Using express.json() on webhook routeUse express.raw({ type: 'application/json' }) — JSON parsing breaks signature verification
Returning non-200 for rejected emailsAlways return 200 to acknowledge receipt — otherwise Resend retries
Old Resend SDK versionemails.receiving.get() and webhooks.verify() require recent SDK versions — see SDK Version Requirements

Testing

Use Resend's test addresses for development:

  • delivered@resend.dev — Simulates successful delivery
  • bounced@resend.dev — Simulates hard bounce

For security testing, send test emails from non-allowlisted addresses to verify rejection works correctly.

Quick verification checklist: 1. Server is running: curl http://localhost:3000 should return a response 2. Tunnel is working: curl https://<your-tunnel-url> should return the same response 3. Webhook is active: Check status in Resend dashboard → Webhooks 4. Send a test email from an allowlisted address and check server logs

Related Skills

  • For full sending and receiving docs, install the resend skill

Related skills

FAQ

Who is agent-email-inbox for?

Developers using agents to execute agent email inbox workflows from SKILL.md.

When should I use agent-email-inbox?

Use when building any system where email content triggers actions - AI agent inboxes, automated support handlers, email-to-task pipelines, or any workflow processing untrusted in

Is agent-email-inbox safe to install?

Review the Security Audits panel on this page before installing in production.

Securityauditappsec

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.