email — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited email (Agent Skill) and scored it 92/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 2 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 2 flagged
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You are in AUTONOMOUS MODE. Do NOT ask questions. Execute the full pipeline below without pausing for user input. Make reasonable decisions using sensible defaults.
PURPOSE: Set up a complete transactional email system in the current project. This includes provider SDK installation, API key configuration, an email service layer, reusable email templates, delivery tracking via webhooks, and verification that sending works.
INPUT: $ARGUMENTS
The user may specify:
If no arguments, default to Resend with welcome + password-reset + notification templates.
=== PHASE 1: PROJECT DETECTION ===
Step 1.1 — Detect Framework
Scan for project files to determine the tech stack:
| File | Framework | Email Service Location |
|---|---|---|
| package.json with "next" | Next.js | lib/email.ts or src/lib/email.ts |
| package.json with "fastify" | Fastify | src/services/email.service.ts |
| package.json with "express" | Express | src/services/email.service.ts |
| package.json with "nestjs" | NestJS | src/email/email.service.ts |
| requirements.txt with "django" | Django | apps/email/services.py |
| requirements.txt with "fastapi" | FastAPI | app/services/email.py |
| Gemfile with "rails" | Rails | app/mailers/ |
Record: FRAMEWORK, LANGUAGE, PROJECT_ROOT, SERVICE_DIR
Step 1.2 — Check Existing Email Setup
Search for any existing email integration:
If a complete email integration exists, report it and exit. If partial, identify gaps and fill them.
Step 1.3 — Select Provider
If the user specified a provider, use it. Otherwise, auto-select:
Record: PROVIDER
=== PHASE 2: SDK INSTALLATION ===
Step 2.1 — Install Provider SDK
Based on the selected provider:
Resend:
npm install resendpip install resendSendGrid:
npm install @sendgrid/mailpip install sendgridAWS SES:
npm install @aws-sdk/client-ses @aws-sdk/client-sesv2pip install boto3Postmark:
npm install postmarkpip install postmarkerMailgun:
npm install mailgun.js form-datapip install requests (Mailgun uses REST API directly)Step 2.2 — Install Template Engine (if needed)
If the project does not already have a template engine for email rendering:
npm install @react-email/components react-email (for Resend/React projects)OR npm install handlebars (for simpler template needs)
Step 2.3 — Configure Environment Variables
Add to .env.example:
Resend:
RESEND_API_KEY=re_...
[email protected]SendGrid:
SENDGRID_API_KEY=SG....
[email protected]AWS SES:
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
[email protected]Postmark:
POSTMARK_API_KEY=
[email protected]Update config validation if the project uses one.
=== PHASE 3: EMAIL SERVICE ===
Step 3.1 — Create Email Client Module
Create a provider-specific client at the appropriate location:
The client module MUST:
Step 3.2 — Create Email Service Layer
Create the email service with a provider-agnostic interface:
class EmailService {
async send(params: {
to: string | string[];
subject: string;
html: string;
text?: string;
from?: string;
replyTo?: string;
tags?: Record<string, string>;
attachments?: Array<{ filename: string; content: Buffer }>;
}): Promise<{ id: string; success: boolean }>
async sendTemplate(params: {
to: string | string[];
template: string; // template name: "welcome", "password-reset", etc.
data: Record<string, unknown>; // template variables
from?: string;
replyTo?: string;
}): Promise<{ id: string; success: boolean }>
async sendBatch(params: {
messages: Array<{
to: string;
subject: string;
html: string;
text?: string;
}>;
}): Promise<{ ids: string[]; success: boolean }>
}The service MUST:
Step 3.3 — Create Provider Adapter
Implement the provider-specific adapter that EmailService delegates to:
Resend adapter:
SendGrid adapter:
SES adapter:
This adapter pattern allows swapping providers without changing calling code.
=== PHASE 4: EMAIL TEMPLATES ===
Step 4.1 — Create Template Directory
Create an email templates directory:
src/emails/ or emails/templates/emails/app/views/mailers/Step 4.2 — Create Welcome Template
Template name: "welcome" Variables: { userName, appName, loginUrl }
Content structure:
Step 4.3 — Create Password Reset Template
Template name: "password-reset" Variables: { userName, resetUrl, expiryMinutes }
Content structure:
Step 4.4 — Create Notification Template
Template name: "notification" Variables: { userName, title, message, actionUrl, actionText }
Content structure:
Step 4.5 — Create Base Layout
Create a shared base layout that all templates extend:
=== PHASE 5: DELIVERY TRACKING ===
Step 5.1 — Create Webhook Endpoint for Delivery Events
Route: POST /api/webhooks/email (or framework equivalent)
Handle provider-specific delivery events:
Resend events:
SendGrid events:
SES events (via SNS):
The webhook handler MUST:
Step 5.2 — Create Delivery Status Types
Define delivery status enum:
enum EmailDeliveryStatus {
QUEUED // Accepted by provider, not yet sent
SENT // Sent to recipient's mail server
DELIVERED // Confirmed delivery to inbox
OPENED // Recipient opened the email (if tracking enabled)
CLICKED // Recipient clicked a link (if tracking enabled)
BOUNCED // Hard bounce — address invalid
DEFERRED // Soft bounce — temporary failure, will retry
DROPPED // Provider rejected (suppression list, invalid)
COMPLAINED // Recipient marked as spam
}Step 5.3 — Create Suppression List Handler
Create a module that manages email suppression:
=== PHASE 6: VERIFICATION ===
Step 6.1 — Static Verification
Run the project's type checker and linter:
Step 6.2 — Integration Checklist
Verify and report:
=== OUTPUT ===
Print the following summary:
Framework: [detected framework] Provider: [selected provider] Templates created: [list]
| File | Purpose |
|---|---|
| [path] | [description] |
| Variable | Purpose | Where to get it |
|---|---|---|
| [KEY] | [purpose] | [provider dashboard URL] |
| EMAIL_FROM | Default sender address | Must match verified domain |
| Template | Variables | Usage |
|---|---|---|
| welcome | userName, appName, loginUrl | After user registration |
| password-reset | userName, resetUrl, expiryMinutes | Password reset request |
| notification | userName, title, message, actionUrl | General notifications |
import { emailService } from './services/email.service';
await emailService.sendTemplate({
to: user.email,
template: 'welcome',
data: { userName: user.name, appName: 'MyApp', loginUrl: 'https://myapp.com/login' },
});To send from your own domain:
=== NEXT STEPS ===
After email integration:
/auth-provider to add authentication with email verification flows."/push-notifications to add push as a complementary notification channel."/analytics-tracking to track email open rates and engagement."/integrate audit to check overall integration health."=== DO NOT ===
============================================================ SELF-HEALING VALIDATION (max 3 iterations) ============================================================
After completing the integration, validate:
IF STILL FAILING after 3 iterations:
============================================================ SELF-EVOLUTION TELEMETRY ============================================================
After producing output, record execution metadata for the /evolve pipeline.
Check if a project memory directory exists:
~/.claude/projects/skill-telemetry.md in that memory directoryEntry format:
### /email — {{YYYY-MM-DD}}
- Outcome: {{SUCCESS | PARTIAL | FAILED}}
- Self-healed: {{yes — what was healed | no}}
- Iterations used: {{N}} / {{N max}}
- Bottleneck: {{phase that struggled or "none"}}
- Suggestion: {{one-line improvement idea for /evolve, or "none"}}Only log if the memory directory exists. Skip silently if not found. Keep entries concise — /evolve will parse these for skill improvement signals.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.