resend-setup ยท git:20260423.a069538 ยท 2026-04-23 ยท sha256 3d707234ea76946b

resend-setup git:20260423.a069538A

Immutable. This exact content is served forever at /api/v1/blob/3d707234ea76946b.

---
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
  ```

  This returns JSON with a `callbackUrl` field โ€” use that as the webhook URL.

- **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.

#### 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.