# OpenClaw

> Give your OpenClaw AI agent an inbox with MailBlastr — send reports, parse newsletters and receipts, and receive replies via signed webhooks, with a leveled security model.

This guide shows how to give an [OpenClaw](https://openclaw.ai) AI agent its own email inbox backed by MailBlastr — so it can send and receive mail with a dedicated address instead of borrowing your credentials.

## Why give your agent an inbox?

An inbox lets your agent:

- **Sign up for its own accounts** on GitHub, hosting platforms, and more, so you never share your personal credentials.
- **Process attachments** such as receipts and invoices, and act on them.
- **Receive newsletters**, parse them, and forward the important parts to you.
- **Send daily reports and digests**.
- **Send and receive email** as a first-class capability.

## Step 1: Get an API key

Create a [MailBlastr API key](https://www.mailblastr.com/docs/api/api-keys-create) for the agent. Scope it to a dedicated project if you want to sandbox the agent away from your production sending.

> **Warning:** Do not paste the key into the chat. SSH into the agent’s machine and store it in an `.env` file, or put it in a password manager (e.g. a 1Password service account) the agent can read from its own vault.

## Step 2: Verify a domain

Your agent needs an address to send from and receive at. We strongly recommend a **subdomain** (`agent.example.com`) rather than the root domain, especially if you want to receive mail, so the agent’s sending reputation stays isolated from your primary domain.

1. **Add the domain** — Create the subdomain via [POST /domains](https://www.mailblastr.com/docs/api/domains-create) or the dashboard, choosing the region closest to your agent.
2. **Add the DNS records** — MailBlastr returns SPF, DKIM, and (for receiving) MX records. Add them at your DNS provider. See [Managing domains](https://www.mailblastr.com/docs/domains/managing).
3. **Enable receiving** — If the agent should receive mail, enable inbound on the domain and add the MX record MailBlastr provides — not just sending records.
4. **Wait for verification** — Verification usually completes within minutes (up to 72 hours for DNS to propagate). Poll [GET /domains/:id](https://www.mailblastr.com/docs/api/domains-get) until `status` is `verified`.

Once verified, store the address in the agent’s memory and have it send you a test email to confirm sending works.

## Step 3: Receive email via webhooks

At this point the agent can send but not receive. To receive, register a [webhook](https://www.mailblastr.com/docs/webhooks/overview) for the `email.received` event pointing at a public URL. During development, expose a local server with a tunnel such as Tailscale Funnel:

```bash
tailscale funnel 3000
# gives a stable public URL like https://hostname.tailnet-name.ts.net
```

```bash
curl -X POST 'https://api.mailblastr.com/webhooks' \
  -H "Authorization: Bearer $MAILBLASTR_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "endpoint_url": "https://hostname.tailnet-name.ts.net/api/webhook",
    "events": ["email.received"]
  }'
```

> **Warning:** When MailBlastr returns the webhook signing secret, store it securely (the same way you stored the API key) — never paste it into the chat.

A minimal handler verifies the signature, applies a sender allowlist, fetches the full inbound email, then notifies you:

```js
import crypto from 'node:crypto';
import { MailBlastr } from 'mailblastr';

const API_KEY = process.env.MAILBLASTR_API_KEY;
const WEBHOOK_SECRET = process.env.MAILBLASTR_WEBHOOK_SECRET; // 'whsec_...'
const mb = new MailBlastr(API_KEY);

// Security: strict allowlist
const ALLOWED_SENDERS = ['your@email.com'];

// Verify the Svix-style signature over `${id}.${timestamp}.${payload}`.
function verify(payload, h) {
  const signed = `${h.id}.${h.timestamp}.${payload}`;
  const secret = Buffer.from(WEBHOOK_SECRET.split('_')[1], 'base64');
  const expected = crypto.createHmac('sha256', secret).update(signed).digest('base64');
  // header looks like "v1,<sig> v1,<sig2>" — accept if any matches
  return h.signature.split(' ').some((s) => s.split(',')[1] === expected);
}

async function handler(req) {
  const payload = await req.text();
  const h = {
    id: req.headers.get('svix-id'),
    timestamp: req.headers.get('svix-timestamp'),
    signature: req.headers.get('svix-signature'),
  };
  if (!h.id || !h.timestamp || !h.signature || !verify(payload, h)) {
    return new Response('Invalid signature', { status: 400 });
  }

  const event = JSON.parse(payload);
  if (event.type === 'email.received') {
    if (!ALLOWED_SENDERS.includes(event.data.from.toLowerCase())) {
      return new Response('OK', { status: 200 }); // ignore, but ack
    }
    // Fetch the full inbound email with the SDK.
    const { data: email } = await mb.emails.receiving.get(event.data.email_id);
    await notifyUser(email);
  }

  return new Response('OK', { status: 200 });
}
```

> **Note:** For production, deploy the handler behind a stable URL and register it via [POST /webhooks](https://www.mailblastr.com/docs/webhooks/overview). See [Receiving email](https://www.mailblastr.com/docs/webhooks/overview) for full inbound payloads, bodies, and attachments.

## Step 4: Instant notifications via OpenClaw

Rather than polling its inbox on a cron, your agent can use OpenClaw’s Gateway API to be notified the instant MailBlastr delivers an `email.received` webhook — turning each inbound message into a real-time prompt. Wire your webhook handler to call the Gateway API, then send a test email to confirm the agent reacts immediately.

## Security considerations

An agent inbox is powerful, and inbound email is an untrusted input — **prompt injection via email is a real risk**. MailBlastr signs every webhook so you can reject forged payloads, but you also need a policy for what the agent does with verified mail. Choose a security level and start strict:

1. **Strict allowlist** — Only act on email from specific known senders. Recommended for most use cases.
2. **Domain allowlist** — Act on email from any sender at a trusted domain (e.g. anyone at example.com).
3. **Content filtering with sanitization** — Accept email from anyone, but sanitize the body to strip likely injection attempts before the agent reads it.
4. **Sandboxed processing** — Process all email, but in a restricted context where the agent has limited capabilities and tools.
5. **Human-in-the-loop** — Process all email but require human approval before the agent takes any action.

> **Warning:** Begin with the strict allowlist and only loosen it if a use case demands it. Always verify the webhook signature before trusting a payload — see [Verify webhooks](https://www.mailblastr.com/docs/webhooks/verify).
