All skills
resend avatar

/agent-email-inbox

@4b1558d official
by resendresend/resend-skills193 stars
28

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.

Use this Skill: https://skilld.dev/gh/resend/resend-skills/agent-email-inbox

This session only. Nothing lands on disk.

referencesadvanced-patterns.md

≈985 tokens on demand. Your agent reads this file only when SKILL.md points to it.

Advanced Patterns — Rate Limiting, Content Limits, Troubleshooting

Rate Limiting per Sender

Prevent any single sender from overwhelming your agent with emails:

const rateLimiter = new Map<string, { count: number; resetAt: Date }>();

function checkRateLimit(sender: string, maxPerHour: number = 10): boolean {
  const now = new Date();
  const entry = rateLimiter.get(sender);

  if (!entry || entry.resetAt < now) {
    rateLimiter.set(sender, { count: 1, resetAt: new Date(now.getTime() + 3600000) });
    return true;
  }

  if (entry.count >= maxPerHour) {
    return false;
  }

  entry.count++;
  return true;
}

Content Length Limits

Prevent token stuffing by truncating oversized email content:

const MAX_BODY_LENGTH = 10000;  // Prevent token stuffing

function truncateContent(content: string): string {
  if (content.length > MAX_BODY_LENGTH) {
    return content.slice(0, MAX_BODY_LENGTH) + '\n[Content truncated for security]';
  }
  return content;
}

Stripping Quoted Threads

Before analyzing email content for safety, strip quoted reply threads. Old instructions buried in > quoted sections or On [date], [person] wrote: blocks could contain unintended directives hidden in legitimate-looking reply chains.

function stripQuotedContent(text: string): string {
  return text
    // Remove lines starting with >
    .split('\n')
    .filter(line => !line.trim().startsWith('>'))
    .join('\n')
    // Remove "On ... wrote:" blocks
    .replace(/On .+wrote:[\s\S]*$/gm, '')
    // Remove "From: ... Sent: ..." forwarded headers
    .replace(/^From:.+\nSent:.+\nTo:.+\nSubject:.+$/gm, '');
}

This is critical for Level 3+ security. Even emails from trusted senders can contain quoted sections with malicious content.

Troubleshooting

"Cannot read properties of undefined (reading 'verify')"

Cause: Resend SDK version too old — resend.webhooks.verify() was added in recent versions. Fix: Update to the latest SDK:

npm install resend@latest

Or use the Svix fallback (see webhook-setup.md).

"Cannot read properties of undefined (reading 'get')"

Cause: Resend SDK version too old — emails.receiving.get() requires a recent SDK. Fix:

npm install resend@latest
# Verify version:
npm list resend

Webhook returns 400 errors

Possible causes:

  1. Wrong signing secret — The signing secret is returned when you create the webhook via the API (data.signing_secret). If you've lost it, delete and recreate the webhook to get a new one.
  2. Body parsing issue — You must use the raw body for verification. Use express.raw({ type: 'application/json' }) on the webhook route, not express.json().
  3. SDK version too old — Update to resend@latest.

ngrok connection refused / tunnel died

Cause: Free ngrok tunnels time out and change URLs on restart. Fix: Restart ngrok, then delete and recreate the webhook via the API with the new tunnel URL. Better: Use Tailscale Funnel or deploy to production.

Email received but no webhook fires

  1. Check the webhook is "Active" in Resend dashboard → Webhooks
  2. Check the endpoint URL is correct (including the path, e.g., /webhook)
  3. Check the tunnel is running: curl https://<your-tunnel-url>
  4. Check the "Recent Deliveries" section on your webhook for status codes

Security check rejecting all emails

  1. Check the sender address is in your ALLOWED_SENDERS list
  2. Check for case mismatch — the comparison should be case-insensitive
  3. Debug by logging: console.log('Sender:', event.data.from.toLowerCase())

Agent doesn't auto-respond to emails

This is expected behavior. The webhook delivers a notification to the user, who then instructs the agent how to respond. This is the safest approach — the user reviews each email before the agent acts on it.

Source: SKILL.md on GitHub

1 alert17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill provides a secure framework for AI agents to process inbound emails via Resend. It includes comprehensive security patterns to mitigate risks from untrusted content, such as allowlists, content filtering, and sandboxing.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: MEDIUM · 2 issues

  • Runlayer6mo

    1/1 file flagged

  • ZeroLeaks5mo

    1 finding · Score: 69/100

Signed by skilld at 4b1558d. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 days ago.

Activeupdated 2 months ago
references
[
  "security-levels.md",
  "webhook-setup.md",
  "advanced-patterns.md"
]
Other metadata
metadata
{
  "author": "resend",
  "version": "3.0.4",
  "homepage": "https://resend.com/agent-skills",
  "source": "https://github.com/resend/resend-skills",
  "openclaw": {
    "primaryEnv": "RESEND_API_KEY",
    "requires": {
      "env": [
        "RESEND_API_KEY"
      ]
    },
    "envVars": [
      {
        "name": "RESEND_API_KEY",
        "required": true,
        "description": "Resend API key for sending and receiving emails"
      },
      {
        "name": "RESEND_WEBHOOK_SECRET",
        "required": false,
        "description": "Webhook signing secret for verifying inbound email event payloads"
      },
      {
        "name": "SECURITY_LEVEL",
        "required": false,
        "description": "Security level for inbound email processing (strict, moderate, permissive)"
      },
      {
        "name": "ALLOWED_SENDERS",
        "required": false,
        "description": "Comma-separated list of allowed sender email addresses"
      },
      {
        "name": "ALLOWED_DOMAINS",
        "required": false,
        "description": "Comma-separated list of allowed sender domains"
      },
      {
        "name": "OWNER_EMAIL",
        "required": false,
        "description": "Owner email address for forwarding or notifications"
      }
    ],
    "links": {
      "repository": "https://github.com/resend/resend-skills",
      "documentation": "https://resend.com/docs/agent-email-inbox-skill"
    }
  }
}
inputs
[
  {
    "name": "RESEND_API_KEY",
    "description": "Resend API key for sending and receiving emails. Get yours at https://resend.com/api-keys",
    "required": true
  },
  {
    "name": "RESEND_WEBHOOK_SECRET",
    "description": "Webhook signing secret for verifying inbound email event payloads. Returned as `signing_secret` in the response when you create a webhook via the API.",
    "required": false
  }
]

README badge

README badge for resend/resend-skills/agent-email-inbox

Receives and processes inbound emails via Resend webhooks with configurable security levels (allowlist, domain, content filtering, sandboxed, human-in-the-loop). Useful for AI agent inboxes, support automation, and email-to-task pipelines where untrusted senders must be handled safely.

Generated from the current SKILL.md.

Does this skill work with custom domains or only Resend-managed addresses?
Both. You can use Resend's auto-generated address (`<anything>@<your-id>.resend.app`) with no DNS setup, or configure a custom domain by adding an MX record and enabling receiving in the Resend dashboard.
What happens if an email arrives from an untrusted sender?
The skill supports multiple security levels. Level 1 (strict allowlist) rejects emails from unauthorized senders. Levels 2-5 offer progressively more flexibility with trade-offs in security. You choose the level before setting up your webhook.
Does this skill verify webhook signatures to prevent spoofing?
Yes. The skill includes `webhooks.verify()` to validate inbound webhook events using the Resend webhook signing secret. You must use the raw request body (not JSON-parsed) for verification to work.
What SDK versions are required?
Node.js requires `resend` >= 6.9.2. Python, Go, Ruby, PHP, Rust, Java, and .NET have minimum version requirements listed in the skill docs. Always use the latest version available.
Can I use this skill with an existing Resend account that sends emails for other projects?
Yes. The skill recommends creating domain-scoped API keys so that even if the key leaks, it can only send from one domain, isolating the agent's access from your other projects.

Generated from the current SKILL.md. These answers refresh after source changes.