# OpenClaw

> Give your OpenClaw AI agent an inbox with SendPing — 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 SendPing — 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 [SendPing API key](https://www.sendping.co/docs/create-an-api-key) for the agent from the dashboard — key creation is a human, signed-in step, so the agent cannot mint its own key (or widen the one you give it). Scope it to a dedicated domain 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.sendping.co/docs/api/domains-create) or the dashboard, choosing the region closest to your agent.
2. **Add the DNS records** — SendPing returns SPF, DKIM, and (for receiving) MX records. Add them at your DNS provider. See [Managing domains](https://www.sendping.co/docs/domains/managing).
3. **Enable receiving** — If the agent should receive mail, enable inbound on the domain and add the MX record SendPing 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.sendping.co/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.sendping.co/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://www.sendping.co/api/webhooks' \
  -H "Authorization: Bearer $SENDPING_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "endpoint": "https://hostname.tailnet-name.ts.net/api/webhook",
    "events": ["email.received"]
  }'
```

> **Warning:** When SendPing 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 { SendPing, verifyWebhookSignature } from 'sendping';

const API_KEY = process.env.SENDPING_API_KEY;
const WEBHOOK_SECRET = process.env.SENDPING_WEBHOOK_SECRET; // 'whsec_...'
const mb = new SendPing(API_KEY);

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

async function handler(req) {
  // The raw body string — never a re-serialized JSON object, or the signature
  // will not match.
  const payload = await req.text();
  // verifyWebhookSignature accepts a Fetch Headers instance directly (5.1+
  // iterates it); the plain-object unpack below is just explicit about which
  // headers matter.
  const headers = {
    'svix-id': req.headers.get('svix-id'),
    'svix-timestamp': req.headers.get('svix-timestamp'),
    'svix-signature': req.headers.get('svix-signature'),
  };

  // Checks the HMAC and (by default) rejects a timestamp more than 5 minutes
  // out. `reason` names the failure, e.g. 'no_match' or 'missing_headers'.
  const { valid, reason } = verifyWebhookSignature(payload, headers, WEBHOOK_SECRET);
  if (!valid) {
    return new Response(`Invalid signature: ${reason}`, { 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.sendping.co/docs/webhooks/overview). See [Receiving email](https://www.sendping.co/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 SendPing 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**. SendPing 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.sendping.co/docs/webhooks/verify).
