email-with-resend
Implement or audit Resend email with templates, queues, preferences, audiences, campaigns, webhooks, and delivery safety. Use when an app needs consent-aware email or Resend repair.
- Category
- infrastructure
- Package
- email-with-resend/SKILL.md
- License
- MIT
- Author
- @tushaarmehtaa
- Tags
- emailresendtransactionalcampaignsdeliverabilitypreferences
Install
Swipe for more runtimes.
Codex
Skills directory: ~/.codex/skills
Install globally
npx skills add tushaarmehtaa/tushar-skills --skill email-with-resend -g -a codex -yInvoke
$email-with-resend or /skillsYou can also describe the task naturally; runtimes may select the skill from its description.
Required access
Claude Code
Skills directory: ~/.claude/skills
Install globally
npx skills add tushaarmehtaa/tushar-skills --skill email-with-resend -g -a claude-code -yInvoke
/email-with-resendYou can also describe the task naturally; runtimes may select the skill from its description.
Required access
Cursor
Skills directory: ~/.cursor/skills
Install globally
npx skills add tushaarmehtaa/tushar-skills --skill email-with-resend -g -a cursor -yInvoke
/email-with-resendYou can also describe the task naturally; runtimes may select the skill from its description.
Required access
local coding agent required
This skill requires project files, terminal commands, and network access. Uploading it to a chat app does not provide equivalent execution.
ChatGPT Skills
This workflow needs a local coding environment or capabilities that a chat-only Skills upload does not provide.
Why local agent required →Instructions
Source: SKILL.mdEmail with Resend
Implement email as a reliable, permission-aware subsystem. This is not a cold-outreach workflow.
Workflow
- Inspect framework/runtime, installed Resend SDK version, queues/jobs, database and user fields, auth/admin roles, existing templates, email events, consent/preferences, suppression data, webhooks, and verified-domain configuration.
- Classify each requested message as transactional, security, lifecycle, or marketing. Do not scaffold re-engagement or campaigns by default. Ask about sender identity, jurisdiction/consent, and preference policy only when not established by the product.
- Read the Resend guide for current send/batch/webhook patterns, suppression handling, unsubscribe design, and copy guidance relevant to the selected class.
- Centralize provider calls. Detect the installed SDK API, handle both returned
errorvalues and thrown transport/runtime errors, use idempotency keys for event-triggered sends, and return a typed result to the caller. - Escape untrusted template values or use React/provider templates. Generate both HTML and useful text. Keep sender/reply-to configuration server-side and use a verified sending subdomain where appropriate.
- Do not block or silently abandon the primary transaction. Use a durable outbox/queue, or a runtime-supported post-response primitive with observability when loss is acceptable. Unawaited promises are not reliable in serverless runtimes.
- For campaigns, use contacts/audiences or a durable campaign job rather than a long request loop. Enforce consent, preferences, suppression, per-recipient idempotency, rate limits, cancellation, and an audit record. Require role-based admin authorization and confirmation of segment/count before send.
- Verify Resend webhook signatures over the raw body, deduplicate events, and process bounces/complaints/delivery failures into a suppression model. Never trust an unsigned event.
- Provide one-click unsubscribe and preference handling where required. Do not expose raw email addresses in URLs when an opaque signed identifier can be used. Keep transactional/security opt-outs separate from marketing preferences.
Verification
Test provider success plus returned API error, thrown network error, duplicate event, queue retry, invalid recipient, escaped user content, text rendering, verified sender/reply-to, signed/invalid/replayed webhook, bounce/complaint suppression, unsubscribe/preferences, unauthorized campaign access, segment preview, and rate-limit behavior. Run repository lint/type/test/build commands and send only to designated test recipients until production setup is confirmed.
Output
Report message classes and triggers, files/templates/jobs changed, sender and environment-variable names, consent/preferences/suppression behavior, webhook and idempotency design, verification evidence/message IDs, and remaining DNS/dashboard/production checks.
Bundled references
1 file · 139 lines
references/guide.md
source ↗Resend implementation guide
Read only the sections needed for the selected transactional, lifecycle, or marketing email path. Check the installed Resend SDK and current primary documentation before using API field names.
Contents
- Send wrapper
- Templates and idempotency
- Durable delivery
- Campaigns
- Webhooks and suppression
- Preferences and unsubscribe
- Copy guidance
- Verification
Send wrapper
Current Resend Node SDK calls return { data, error } for API failures and may also throw for runtime/transport failures. The SDK uses replyTo in Node options.
import { Resend } from 'resend';
const resend = new Resend(process.env.RESEND_API_KEY);
type SendResult =
| { ok: true; id: string }
| { ok: false; retryable: boolean; message: string };
export async function sendEmail(input: {
to: string | string[];
subject: string;
html: string;
text: string;
idempotencyKey: string;
}): Promise<SendResult> {
try {
const { data, error } = await resend.emails.send(
{
from: process.env.EMAIL_FROM!,
replyTo: process.env.EMAIL_REPLY_TO,
to: input.to,
subject: input.subject,
html: input.html,
text: input.text,
},
{ idempotencyKey: input.idempotencyKey },
);
if (error || !data?.id) {
return classifyResendError(error);
}
return { ok: true, id: data.id };
} catch (error) {
return classifyTransportError(error);
}
}
Adapt the second-argument/idempotency signature to the installed SDK version. Do not return success merely because the promise resolved.
Templates and idempotency
Prefer React Email or provider templates for structured escaping. If generating HTML manually, escape every untrusted name, URL, and content value. Include a useful text alternative and one primary action.
Derive idempotency keys from the logical event, for example welcome:{userId}:{signupEventId}. Store send intent/status locally when delivery matters beyond Resend’s idempotency retention window.
Use a verified sending domain/subdomain and a monitored reply-to. SPF and DKIM are required for domain verification; add DMARC according to the domain’s delivery policy. Treat dashboard/DNS status as manual until observed.
Durable delivery
For user actions, write an outbox row in the same transaction as the triggering state change. A worker sends, records the Resend message ID, and retries classified transient failures with backoff. Use a dead-letter/alert path for permanent exhaustion.
Runtime-specific post-response primitives can be acceptable for low-value notifications, but an unawaited promise may be terminated in serverless environments. Do not hold a signup request open for network email delivery unless the email itself is the security transaction and the UX is designed for it.
Campaigns
Marketing/lifecycle email requires consent or another documented lawful basis and a product preference policy. Before send:
- materialize/preview the segment and recipient count;
- require role-based admin authorization and confirmation;
- create a campaign/run ID;
- enqueue one idempotent recipient job or use Resend Broadcasts/Contacts for marketing campaigns;
- filter current preferences and suppression at send time;
- record sent/skipped/failed counts without returning recipient PII broadly.
Resend’s Batch API can send up to the current documented limit per request and is suited to multiple transactional messages. Current Resend guidance recommends Broadcasts for marketing campaigns. Do not implement a long request loop with setTimeout as a campaign queue.
Webhooks and suppression
Verify Resend/Svix signatures using the raw request body and webhook secret before parsing/processing.
export async function POST(req: Request) {
const payload = await req.text();
let event;
try {
event = resend.webhooks.verify({
payload,
headers: {
id: req.headers.get('svix-id')!,
timestamp: req.headers.get('svix-timestamp')!,
signature: req.headers.get('svix-signature')!,
},
webhookSecret: process.env.RESEND_WEBHOOK_SECRET!,
});
} catch {
return new Response('Invalid signature', { status: 400 });
}
await processResendEventIdempotently(event);
return new Response('OK');
}
Use webhook/event ID for deduplication. data.to may contain multiple recipients; normalize addresses. Suppress hard bounces and complaints immediately, track transient delivery failures separately, and avoid equating a bounce with a user’s global marketing preference.
Preferences and unsubscribe
Model preferences by purpose/topic, with a global marketing opt-out and a separate suppression state. Security and essential transactional messages should not be disabled by a marketing opt-out.
Use an opaque, random or signed preference token that resolves server-side rather than placing raw email in the URL. Validate signatures in constant time, support key rotation/expiry policy, and provide a confirmation/preferences page. Add standards-compliant List-Unsubscribe and one-click behavior where applicable.
Copy guidance
- State why the recipient is receiving the message.
- Keep subject lines factual; avoid false urgency or fabricated personalization.
- One primary action is usually enough.
- Re-engagement should mention a real product change or user state, not placeholders.
- Do not infer “power”, “churned”, or “inactive” solely from simplistic percentiles; define segments from product behavior and validate queries.
Verification
- Test
{ data, error }and thrown-error paths. - Confirm idempotency prevents duplicate logical sends.
- Verify HTML escaping, text rendering, sender, reply-to, and test recipient delivery.
- Test valid/invalid/replayed webhooks and multi-recipient payloads.
- Test bounce/complaint suppression and preference/unsubscribe paths.
- Test unauthorized campaign access, segment preview, duplicate run, retry, cancellation, and rate limits.