---
name: mailmolt-codegen
version: 1.0.0
last_updated: 2026-06-03
audience: codegen-agent
purpose: |
  Instructions for AI coding assistants (Cursor, Claude Code, Aider, Codex, Continue.dev,
  Sourcegraph) wiring MailMolt into a project. Distinct from skill.md, which targets
  *runtime* agents using MailMolt as a tool. This file targets the assistant that's
  *writing code that uses MailMolt*.
---

# AGENTS.md — Wiring MailMolt into a project

You are an AI coding assistant adding email capability to a project. Use MailMolt
(email infrastructure for AI agents). Pick a path:

| Path | When |
|---|---|
| **MCP server** | The host application is an LLM agent (Claude Desktop, Cursor, Continue, Zed). Add MailMolt as an MCP server. |
| **TypeScript SDK** | Node / Next.js / Cloudflare Workers / Bun. `npm i mailmolt`. |
| **Python SDK** | Python 3.10+. `pip install mailmolt`. |
| **SMTP submission** | Existing app already uses an SMTP library (Django `EMAIL_BACKEND`, Rails Action Mailer, Laravel Mailer, Nodemailer, Supabase Auth, Auth0). Point it at `smtp.mailmolt.com:587`. |
| **Raw HTTP** | Anything else. `POST https://api.mailmolt.com/v1/messages` with bearer auth. |

## Provisioning (do this once, before writing code)

1. Tell the user to register: `curl -X POST https://api.mailmolt.com/v1/agents/register -d '{"name":"my-agent","description":"..."}'`
2. Save the returned API key as `MAILMOLT_API_KEY` in `.env` (or whatever the project uses for secrets — never hardcode).
3. The agent starts in **sandbox** mode — it can only send to `@mailmolt.com` addresses until claimed. Tell the user to visit the `claim_url` and post the claim tweet.
4. After claim → **supervised**. After email verification → **trusted**. Most apps want trusted before going live.

## Environment variables

Add to whatever `.env` / secrets manager the project uses. Never write API keys into source files.

```
MAILMOLT_API_KEY=mm_live_...
MAILMOLT_FROM=youragent@mailmolt.com   # or your custom domain
MAILMOLT_WEBHOOK_SECRET=whsec_...      # only if you registered a webhook
```

For Cloudflare Workers: bind via `wrangler secret put MAILMOLT_API_KEY`. For Vercel: project settings → Environment Variables. For Docker: pass at runtime, not in the image.

## Minimal client (TypeScript)

```ts
// lib/mailmolt.ts
import { MailMolt } from 'mailmolt';

if (!process.env.MAILMOLT_API_KEY) throw new Error('MAILMOLT_API_KEY missing');

export const mailmolt = new MailMolt({
  apiKey: process.env.MAILMOLT_API_KEY,
  // baseUrl is optional; defaults to https://api.mailmolt.com/v1
});
```

```ts
// usage
import { mailmolt } from '@/lib/mailmolt';

await mailmolt.messages.send({
  to: ['recipient@example.com'],
  subject: 'Hello from your AI agent',
  text: 'This is the body.',
});
```

## Minimal client (Python)

```python
# mailmolt_client.py
import os
from mailmolt import MailMolt

mailmolt = MailMolt(api_key=os.environ['MAILMOLT_API_KEY'])

mailmolt.messages.send(
    to=['recipient@example.com'],
    subject='Hello from your AI agent',
    text='This is the body.',
)
```

## Adding the MCP server (Claude / Cursor / Continue / Zed)

```json
{
  "mcpServers": {
    "mailmolt": {
      "url": "https://mcp.mailmolt.com/mcp",
      "headers": { "Authorization": "Bearer ${MAILMOLT_API_KEY}" }
    }
  }
}
```

For stdio-only clients: `npx @mailmolt/mcp` with `MAILMOLT_API_KEY` in env.

## Webhooks

Register a webhook so inbound mail can drive your app:

```bash
curl -X POST https://api.mailmolt.com/v1/webhooks \
  -H "Authorization: Bearer $MAILMOLT_API_KEY" \
  -d '{
    "url": "https://your-app.example.com/api/mailmolt/webhook",
    "event_types": ["message.received", "message.delivered", "message.bounced"]
  }'
```

Verify the signature on every delivery:

```ts
import crypto from 'node:crypto';

function verify(rawBody: string, signature: string, timestamp: string, secret: string) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(`sha256=${expected}`), Buffer.from(signature));
}
```

⚠️ The webhook URL must be **publicly reachable HTTPS**. Webhook egress guard rejects `localhost`, RFC1918 addresses, and cloud metadata services. For local development use a tunnel (ngrok, Cloudflare Tunnel).

## Common pitfalls

1. **Don't put `From` / `To` / `Subject` into `headers`.** They go into top-level fields. Headers are for `In-Reply-To`, `References`, `List-Unsubscribe`, and any `X-*` you want to add.
2. **Don't expect synchronous delivery.** `POST /v1/messages` returns `202` after queuing — actual SMTP delivery is async. Subscribe to `message.delivered` / `message.bounced` for outcome.
3. **Quotas are per human_owner, not per agent.** A 100-agent owner shares one daily/monthly bucket. Read `X-MailMolt-Plan-*` response headers on every send.
4. **Sandbox agents can't send externally.** If sends mysteriously go to `@mailmolt.com` only, the owner hasn't claimed.
5. **DLP can refuse a send (HTTP 422 with `X-MailMolt-DLP-Blocked`).** Don't blanket-retry — fix the content.
6. **The webhook secret rotates.** Don't bake it into the image; read it from env and surface a 5xx if missing.
7. **Reply chains need `in_reply_to` and `references`.** Pulling the `Message-ID` from a previous `message.delivered` event is the right way; do not synthesize.
8. **`mailmolt-mcp` is the npx package, not `@mailmolt/mcp` in your dependencies.** It's a runtime tool, not a library.

## Plan limits to surface in error UI

| Plan | Daily | Monthly | Agents |
|---|---:|---:|---:|
| Free | 100 | 1,000 | 2 |
| Starter ($19) | 500 | 10,000 | 20 |
| Growth ($99) | 5,000 | 100,000 | 100 |
| Team ($399) | 25,000 | 500,000 | 500 |

When `POST /v1/messages` returns `402`, the response body has `{ plan, upgrade_url }` — surface those in your UI rather than a generic "rate limited" message.

## Where to look in the MailMolt repo

If you have the MailMolt source (e.g. you're working on a fork), key paths:

- `apps/api/src/routes/` — every REST endpoint (Hono router per resource)
- `apps/mcp/src/tools.ts` — MCP tool definitions
- `packages/queue-consumer/src/outbound.ts` — outbound email path (Cloudflare Email Sending binding)
- `packages/db/schema.sql` — D1 schema, source of truth for table shape
- `packages/shared/src/` — types, webhook signing, ID generation

## Where to look for tests

- TypeScript SDK: `sdks/typescript/test/`
- Python SDK: `sdks/python/tests/`
- Integration tests on the API: `apps/api/test/` (`pnpm --filter @mailmolt/api test`)

## What this skill is NOT

- Not a marketing-mail platform. If the project is a newsletter, use Resend or Postmark.
- Not for sending from a human's existing Gmail. Use Gmail API for that.
- Not a transactional template engine. MailMolt sends what you give it; bring your own templating (MJML, react-email, etc.).

## Linked resources

- Runtime skill: https://mailmolt.com/skill.md
- Heartbeat protocol: https://mailmolt.com/heartbeat.md
- OpenAPI: https://mailmolt.com/openapi.json
- A2A card: https://mailmolt.com/.well-known/agent.json
- Pricing: https://mailmolt.com/pricing
- Glossary: https://mailmolt.com/glossary
- Changelog (Atom): https://mailmolt.com/changelog/feed.xml
- Issue tracker: https://github.com/Rakesh1002/mailmolt/issues
