resend-setup ยท diff
git:20260423.a069538 to git:20260424.05e9d6e
5 added, 9 removed. Audit A to A.
---
name: resend-setup
description: Set up and send emails via a user-provided Resend account (BYO email provider)
compatibility: "Designed for Vellum personal assistants"
metadata:
emoji: "๐ค"
vellum:
display-name: "Resend Email Setup"
user-invocable: true
---
## Overview
Send emails through the user's own Resend account. This is for **Bring Your Own** email โ the user provides their Resend API key and you send via their domain.
This skill is **not** related to Vellum's managed email (`assistant email` commands). It uses the Resend HTTP API directly.
## Setup
### API Key (for sending)
Use the `credential_store` tool to prompt the user for their API key via the secure UI. **Never ask for the key in chat.**
```
credential_store:
action: "prompt"
service: resend
field: api_key
label: "Resend API Key"
placeholder: "re_xxxxxxxxx"
description: "Your Resend API key for sending emails"
allowed_domains: ["api.resend.com"]
injection_templates:
- hostPattern: "*.resend.com"
injectionType: header
headerName: Authorization
valuePrefix: "Bearer "
```
### Domain Detection
After storing the API key, **automatically detect the user's domain** โ don't ask them for it. Call the Resend Domains API:
```bash
curl -s https://api.resend.com/domains \
-H "Content-Type: application/json"
```
Run this with `network_mode: "proxied"` and the resend credential so the Authorization header is injected automatically. The response contains a `data` array of domain objects with `name` and `status` fields. Pick the first domain with `"status": "verified"` (or the only domain if there's just one). If no verified domains are found, tell the user they need to verify a domain in their Resend dashboard first.
Use `hi@<domain>` as the default sender address (consistent with Vellum's native email convention). Remember the domain for future sends.
### Webhook Setup (for receiving)
If the user also wants to **receive** emails via Resend, you need to get a webhook URL and register it with Resend.
#### Getting the webhook URL
- Check the `IS_PLATFORM` environment variable to determine the approach:
-
- - **If `IS_PLATFORM=true`** (managed assistant): Register a platform callback route:
-
- ```bash
- assistant platform callback-routes register --path webhooks/resend --type resend --json
- ```
+ Use the unified webhooks CLI to get a callback URL. This handles both platform-managed and self-hosted assistants automatically:
- This returns JSON with a `callbackUrl` field โ use that as the webhook URL.
+ ```bash
+ CALLBACK_URL=$(assistant webhooks register resend --source "$DOMAIN")
+ ```
- - **If `IS_PLATFORM` is not set** (self-hosted): Use a tunnel like ngrok to expose the gateway's `/webhooks/resend` endpoint. The public URL from the tunnel is the webhook URL.
+ If the command fails because no public base URL is configured (self-hosted only), load the `public-ingress` skill to walk the user through setting one up, then retry the command.
#### Registering the webhook with Resend
Create the webhook in Resend via their API using the webhook URL from above:
```bash
curl -X POST https://api.resend.com/webhooks \
-H "Content-Type: application/json" \
-d '{
"url": "<webhook URL>",
"events": ["email.received"]
}'
```
Use `network_mode: "proxied"` with the resend credential so the Authorization header is injected automatically.
#### Storing the webhook signing secret
Store the signing secret so the gateway can verify inbound webhooks:
```
credential_store:
action: "prompt"
service: resend
field: webhook_secret
label: "Resend Webhook Signing Secret"
placeholder: "whsec_xxxxxxxxx"
description: "Signing secret from your Resend webhook settings (for verifying inbound emails)"
```
## Sending Email
Use `bash` with `curl` to call the Resend API. The credential proxy injects the `Authorization: Bearer` header automatically when using `network_mode: "proxied"` with the resend credential.
```bash
curl -X POST https://api.resend.com/emails \
-H "Content-Type: application/json" \
-d '{
"from": "Name <sender@example.com>",
"to": ["recipient@example.com"],
"subject": "Hello",
"text": "Plain text body",
"html": "<p>HTML body</p>"
}'
```
### API Parameters
| Parameter | Type | Required | Description |
| ---------- | ------------------ | -------- | --------------------------------------------------------------- |
| `from` | string | โ
| Sender address (`"Name <email>"` format) |
| `to` | string \| string[] | โ
| Recipient(s), max 50 |
| `subject` | string | โ
| Email subject |
| `text` | string | | Plain text body |
| `html` | string | | HTML body |
| `cc` | string \| string[] | | CC recipients |
| `bcc` | string \| string[] | | BCC recipients |
| `reply_to` | string \| string[] | | Reply-to address |
| `headers` | object | | Custom headers (e.g. `In-Reply-To`, `References` for threading) |
### Threading (replies)
To reply in a thread, include `In-Reply-To` and `References` headers:
```json
{
"from": "bot@example.com",
"to": ["user@example.com"],
"subject": "Re: Original subject",
"text": "Reply body",
"headers": {
"In-Reply-To": "<original-message-id>",
"References": "<original-message-id>"
}
}
```
### Response
Success returns `{ "id": "email-id" }` with HTTP 200.
Errors return `{ "message": "error description" }` with 4xx/5xx status.
## Important Notes
- The `from` address must be from a domain verified in the user's Resend account.
- Default sender address is `hi@<domain>` โ use this unless the user specifies otherwise.
- Always confirm with the user before sending โ never send without explicit permission.
- Use `text` for plain text, `html` for rich formatting. Provide both when possible.
- Rate limits depend on the user's Resend plan.