Resend plugin
The Resend plugin lets a Vaubaan Gateway mission use Resend without handing the agent a credential. Outbound email : transactional sends classified by recipient zone, segments and contacts, broadcast campaigns, sending domains — one resource per domain and per segment.
- Version:
0.3.0(package@vaubaan/plugin-resend) - Status: stable
- Health: not enough reports yet — what this means
- Source: plugins/resend, catalog risk-catalog.yaml version 4 of 2026-10-14
- How to connect an account: Connect Resend
- How it is modelled: handbook
One account is one Resend API key; resources are its sending domains and its contact segments. Sends are told apart by who the email goes to (internal, allow-listed, anyone), and the owner of the account labels each domain and segment with an environment so that staging and production are held separately.
Permissions
Each permission is a named risk of the plugin's catalog: a mission holds an explicit list of them, never "all". The severity is computed from the permission's six axes (undo, blast radius, data, cost, visible to, lasts); nothing is decided from it.
| Permission | What it allows | Severity | Why it is a risk |
|---|---|---|---|
resend.read-email-status | Read email send status and metadata | low | Retrieve the status, subject, from/to and tags of a sent email. Metadata-level : GET /emails/:id returns no body content. Low risk. |
resend.read-domains | Read sending domains and DNS verification status | low | List or retrieve the mission's sending domains with their DKIM / SPF / DMARC records and the recipient-zone configuration (describe_zones). Reveals the sending posture ; no secret (DNS records are public). |
resend.read-audiences | Read audiences and contacts (PII) — deprecated, replaced by read-segments | medium (deprecated) | Deprecated : matches no call any more. Resend renamed audiences to segments and made contacts account-level ; `resend.read-segments` carries the same PII read. Kept so the id stays resolvable. |
resend.read-segments | Read segments and contacts (PII) | medium | List or retrieve the mission's segments, the account's contacts and the members of a segment. Contacts carry PII (email, first_name, last_name, custom properties) — GDPR-relevant, every read by an agent is a minimisation question. Distinct from read-broadcasts so a campaign status can be checked without unlocking the contact database. |
resend.read-broadcasts | Read broadcast campaigns | low | List or retrieve broadcast metadata (name, subject, status, schedule) of the mission's segments. No contact-level PII, aggregate campaign information only. |
resend.send-email-internal | Send a transactional email to internal recipients only | low | Every recipient belongs to the sending domain's internal_domains. Low exfiltration risk — the message stays inside the organisation. Side effect : a real email lands in a real inbox. |
resend.send-email-allowlist | Send a transactional email to pre-approved external recipients | medium | Every recipient is internal or matches allowlist_domains / allowlist_addresses of the sending domain. Pre-approved but external : the message leaves the organisation and cannot be recalled. |
resend.send-email-external-unbounded | Send a transactional email to an arbitrary external recipient | high (only for staging, dev) | At least one recipient matches neither internal_domains nor the allowlists. Cardinal exfiltration vector : an agent could put sensitive data in the body and send it to an attacker-controlled address, irreversibly. Acceptable only on domains labelled staging or dev. |
resend.send-batch | Send a batch of transactional emails (up to 100 per call) | high | POST /emails/batch sends up to 100 emails in one call. Bulk amplification whatever the recipient zone — the classifier also emits the zone slice, so both permissions must be held. A distinct marker so the creator consents to bulk sending explicitly. |
resend.audience-write | Create or delete an audience — deprecated, replaced by segment-write | medium (deprecated) | Deprecated : matches no call any more. Resend renamed audiences to segments ; `resend.segment-write` carries the same structural change. Kept so the id stays resolvable. |
resend.segment-write | Create or delete a segment | medium | Structural change to the contact database. Creating a segment is low risk ; deleting one drops every membership it held (the contacts survive). Conservative vector for the worst case. |
resend.contact-write | Create, update or delete contacts ; add or remove segment members | high | Mutate the contact database : add subscribers, edit PII fields, unsubscribe, delete, or move contacts in and out of a segment (which decides who a broadcast reaches). Reversible for creates, not for deletes. |
resend.broadcast-draft | Create or update a broadcast (draft, not sent) | low | Draft a campaign for a segment of the mission. No side effect until sent — the classifier refuses a create carrying `send` or `scheduled_at`, which would bypass broadcast-send. Reversible (delete the draft). |
resend.broadcast-send | Send a broadcast to its segment (mass email delivery) | critical | Deliver a broadcast to every contact of the segment. Cardinal bulk action — potentially thousands of real emails, irreversibly, at a cost that scales with the segment. The plugin re-reads the broadcast upstream and refuses to send one that targets another segment than the one named. The highest-risk operation of this service. |
resend.broadcast-delete | Delete a broadcast | low | Remove a broadcast of a segment of the mission. A sent broadcast loses its record only (delivered emails are not recalled) ; a scheduled one is cancelled. |
resend.domain-write | Add, update or remove a sending domain | high | Posture shift : adding a domain widens what the account can send from ; removing one breaks delivery for every sender on it ; tracking and TLS settings change what recipients see. DNS must be configured outside Resend. Suggested : ask first. |
resend.domain-verify | Trigger DNS verification of a domain | low | Idempotent request that asks Resend to re-check the DNS records of a domain of the mission. No side effect beyond the attempt ; a step of the domain set-up posture shift. |
resend.uncategorized-write | Uncategorized Resend write | medium (the catch-all: touched only by a call no other permission covers) | Catch-all for a write no named permission covers. If Resend adds a surface (webhooks, API keys, templates) and Vaubaan wraps it before the catalog is updated, calls land here — fail-loud by design. Never offered in a preset. |
Presets
A preset pre-fills the permissions of a mission for one account, with a limit per period, a rate and whether each permission runs freely or asks the mission creator first. The person creating the mission adjusts it; the mission stores the explicit list.
Read-only
read-only — Email status, sending domains and campaign metadata of the selected resources. No PII, no write.
| Permission | What it allows | Limit per period | Rate | Runs |
|---|---|---|---|---|
resend.read-email-status | Read email send status and metadata | 2000 | 120 per minute | runs freely |
resend.read-domains | Read sending domains and DNS verification status | 1000 | 60 per minute | runs freely |
resend.read-broadcasts | Read broadcast campaigns | 1000 | 60 per minute | runs freely |
Developer
developer — One mission per code project — transactional sends to internal and allow-listed recipients, generous limits; no bulk, no PII, no domain change.
| Permission | What it allows | Limit per period | Rate | Runs |
|---|---|---|---|---|
resend.read-email-status | Read email send status and metadata | 5000 | 120 per minute | runs freely |
resend.read-domains | Read sending domains and DNS verification status | 2000 | 60 per minute | runs freely |
resend.read-broadcasts | Read broadcast campaigns | 1000 | 60 per minute | runs freely |
resend.send-email-internal | Send a transactional email to internal recipients only | 2000 | 60 per minute | runs freely |
resend.send-email-allowlist | Send a transactional email to pre-approved external recipients | 1000 | 30 per minute | runs freely |
Marketing operator
marketing-operator — Contacts, segments and campaigns; broadcast sends, batch sends and segment deletion ask first. No domain change.
| Permission | What it allows | Limit per period | Rate | Runs |
|---|---|---|---|---|
resend.read-email-status | Read email send status and metadata | 2000 | 120 per minute | runs freely |
resend.read-domains | Read sending domains and DNS verification status | 1000 | 60 per minute | runs freely |
resend.read-segments | Read segments and contacts (PII) | 5000 | 120 per minute | runs freely |
resend.read-broadcasts | Read broadcast campaigns | 2000 | 120 per minute | runs freely |
resend.send-email-internal | Send a transactional email to internal recipients only | 1000 | 60 per minute | runs freely |
resend.send-email-allowlist | Send a transactional email to pre-approved external recipients | 1000 | 30 per minute | runs freely |
resend.send-batch | Send a batch of transactional emails (up to 100 per call) | 50 | 5 per minute | ask me first |
resend.contact-write | Create, update or delete contacts ; add or remove segment members | 5000 | 120 per minute | runs freely |
resend.segment-write | Create or delete a segment | 20 | 5 per minute | ask me first |
resend.broadcast-draft | Create or update a broadcast (draft, not sent) | 200 | 20 per minute | runs freely |
resend.broadcast-send | Send a broadcast to its segment (mass email delivery) | 10 | 1 per minute | ask me first |
resend.broadcast-delete | Delete a broadcast | 50 | 10 per minute | runs freely |
Domain admin
domain-admin — Provision sending domains — read and verify freely, every domain mutation asks first. No send.
| Permission | What it allows | Limit per period | Rate | Runs |
|---|---|---|---|---|
resend.read-domains | Read sending domains and DNS verification status | 2000 | 60 per minute | runs freely |
resend.domain-verify | Trigger DNS verification of a domain | 200 | 10 per minute | runs freely |
resend.domain-write | Add, update or remove a sending domain | 20 | 5 per minute | ask me first |
Tools
| Tool | What it does |
|---|---|
resend__get_email | Read the status of a sent email |
resend__list_domains | List sending domains |
resend__get_domain | Read a sending domain |
resend__list_segments | List segments |
resend__get_segment | Read a segment |
resend__list_contacts | List contacts |
resend__get_contact | Read a contact |
resend__list_broadcasts | List broadcasts |
resend__get_broadcast | Read a broadcast |
resend__describe_zones | Read the recipient zones |
resend__send_email | Send an email |
resend__send_batch_emails | Send a batch of emails |
resend__create_domain | Add a sending domain |
resend__update_domain | Change a sending domain |
resend__delete_domain | Remove a sending domain |
resend__verify_domain | Re-check a sending domain |
resend__create_segment | Create a segment |
resend__delete_segment | Delete a segment |
resend__create_contact | Create a contact |
resend__update_contact | Change a contact |
resend__delete_contact | Delete a contact |
resend__add_contact_to_segment | Add a contact to a segment |
resend__remove_contact_from_segment | Remove a contact from a segment |
resend__create_broadcast | Create a draft broadcast |
resend__update_broadcast | Change a draft broadcast |
resend__send_broadcast | Send a broadcast to its segment |
resend__delete_broadcast | Delete a broadcast |
Health
Health: not enough reports yet. A plugin version is deemed validated by the community with at least 200 reports and 90 % of them successful, over the last 90 days, as reported by the instances whose operators turned community telemetry on. It is a community signal, not a security guarantee.