Illustration for how to migrate openclaw from gmail pub/sub to lobstermail webhooks

how to migrate openclaw from gmail pub/sub to lobstermail webhooks

Replace the Google Cloud Console setup, OAuth tokens, and watch renewals with a single SDK call. Step-by-step migration guide for OpenClaw developers.

7 min read
Samuel Chenard
Samuel ChenardCo-founder

If you built OpenClaw email handling on Gmail Pub/Sub, you've been in at least one of these places: a half-configured Google Cloud project at 11pm, a gog gmail watch serve process that silently lapsed over the weekend, or an OAuth token refresh that broke something in production. The setup works when everything goes right. The problem is all the ways it can quietly go wrong without telling you.

This guide walks through replacing that whole chain with LobsterMail webhooks. The agent hatches its own inbox, you register one endpoint, and Google is completely out of the picture.

If you want the conceptual case for dropping Gmail entirely, this post covers it. This one is for people who have the Gmail setup running today and want concrete steps to switch.

What you're currently maintaining#

The standard OpenClaw Gmail setup is a chain of five dependencies:

  1. A Gmail account (created by a human)
  2. A Google Cloud project with Pub/Sub API enabled
  3. A push subscription pointing at a public HTTPS endpoint
  4. openclaw webhooks gmail run (or the underlying gog gmail watch serve) keeping the watch alive
  5. OAuth tokens that expire and need renewal

When all five are working, your agent gets near-real-time email notifications. When any one breaks, you're diagnosing a chain. Was it the token? Did the watch lapse? Is the subscription still pointed at the right URL? Google's error messages won't tell you which link failed.

The structural issue is that this stack was designed for humans. You created the Gmail account. You enabled the API. You granted OAuth consent. Your agent is borrowing human infrastructure and calling it autonomous.

What the LobsterMail version looks like#

The agent provisions its own inbox. No Cloud Console, no OAuth flow, no human step.

import { LobsterMail } from '@lobsterkit/lobstermail';

const lm = await LobsterMail.create();

// Agent creates its own inbox — no human account required
const inbox = await lm.createInbox();
console.log(inbox.address); // agent_abc@lobstermail.ai

Then register a webhook:

const webhook = await lm.createWebhook({
  url: 'https://your-agent.example.com/hooks/email',
  events: ['email.received'],
});

Warning

The webhook secret is only returned once on creation. Store it in an environment variable immediately — you can't retrieve it again.

That's the entire provisioning step. LobsterMail pushes to your endpoint when email arrives. No watch renewal cycle, no token refresh logic, no Google dependency.

The migration#

Step 1: Install the SDK

npm install lobstermail

Step 2: Provision an inbox

Run this once, or let your agent call it at startup:

import { LobsterMail } from '@lobsterkit/lobstermail';

const lm = await LobsterMail.create();
const inbox = await lm.createInbox();

// Persist inbox.id and inbox.address somewhere durable
// inbox.address is what external services will send to
console.log(inbox.address);

Step 3: Register your webhook

const webhook = await lm.createWebhook({
  url: 'https://your-agent.example.com/hooks/email',
  events: ['email.received'],
});

// Add to your env vars — won't be shown again
// LOBSTERMAIL_WEBHOOK_SECRET=webhook.secret

Step 4: Update your email handler

The LobsterMail webhook payload is simpler than the Gmail Pub/Sub format:

{
  "event": "email.received",
  "timestamp": "2026-03-02T09:00:00Z",
  "data": {
    "emailId": "em_abc123",
    "inboxId": "in_xyz789",
    "from": "sender@example.com",
    "subject": "Your verification code",
    "preview": "First 200 characters of the email body..."
  }
}

Always verify the signature before processing:

import { createHmac } from 'node:crypto';

function verifySignature(body: string, signature: string, secret: string): boolean {
  const expected = createHmac('sha256', secret)
    .update(body)
    .digest('hex');
  return expected === signature;
}

// In your HTTP handler (Express, Hono, Fastify — whatever you're using)
app.post('/hooks/email', async (req, res) => {
  const signature = req.headers['x-lobstermail-signature'] as string;

  if (!verifySignature(req.rawBody, signature, process.env.LOBSTERMAIL_WEBHOOK_SECRET!)) {
    return res.status(401).send('Invalid signature');
  }

  const { event, data } = req.body;

  if (event === 'email.received') {
    await handleEmail(data);
  }

  res.status(200).send('ok');
});

Step 5: Test it

Send a test email to your inbox.address. You should get a webhook delivery within a few seconds. Confirm your handler processes it correctly before moving on.

Tip

Run both setups in parallel for a day or two before decommissioning Gmail. It costs nothing and gives you confidence in the new setup before you pull the plug on the old one.

Step 6: Decommission the Gmail setup

Once LobsterMail is confirmed working:

  • Stop gog gmail watch serve or openclaw webhooks gmail run
  • Delete the Pub/Sub subscription and topic in Google Cloud Console
  • Revoke the OAuth token from your Google account settings
  • Archive or delete the Gmail account if it was created solely for the agent

What changes#

The inbox address changes. You'll have an @lobstermail.ai address instead of a Gmail one. Update any external services that send to the old address — your agent logic downstream stays the same.

One thing to watch: the webhook payload includes a 200-character preview, not the full body. If your existing handler relied on --include-body from the Pub/Sub setup, fetch the full email using the emailId:

if (event === 'email.received') {
  // Get the full body when you need it
  const email = await lm.getEmail(data.emailId);
  await handleEmail(email);
}

Everything else — how your agent processes, responds to, or routes email — stays exactly as it was.

Retry behavior#

LobsterMail retries failed webhook deliveries with exponential backoff, up to 10 attempts. If your endpoint is briefly unavailable, emails aren't lost. After 10 consecutive failures the webhook is auto-disabled. You can re-enable it:

// List webhooks to check status
const webhooks = await lm.listWebhooks();

// Re-enable via API if needed
await fetch('https://api.lobstermail.ai/v1/webhooks/wh_abc123', {
  method: 'PATCH',
  headers: { Authorization: `Bearer ${process.env.LOBSTERMAIL_API_KEY}` },
  body: JSON.stringify({ enabled: true }),
});

Compare that to a lapsed Gmail watch, which fails silently — your agent just stops receiving email and you find out when something downstream breaks.

What I didn't expect#

The mechanical migration is straightforward. What's less obvious until you've done it is how much the mental model simplifies. There's no watch renewal cron to monitor. No question of whether the OAuth token is still valid. No Google Cloud Console tab to keep bookmarked. The agent has an inbox. Email arrives. The webhook fires. That's the whole model.

If the Gmail setup is running smoothly and you're not actively touching it, there's no emergency. But if you're debugging a broken watch, starting a new project, or tired of the maintenance surface area, this is a reasonable morning to make the switch. The free tier covers 1,000 emails per month with no credit card required.


Give your agent its own inbox. Get started with LobsterMail — it's free.

Frequently asked questions

What is OpenClaw Gmail Pub/Sub and why do people migrate away from it?

Gmail Pub/Sub is how OpenClaw receives real-time email notifications using Google Cloud's push subscription system. People migrate away because it requires ongoing maintenance: watch renewals every 7 days, OAuth token management, and a publicly accessible HTTPS endpoint configured before Google will push anything to you.

Do I need a Google Cloud account to use LobsterMail?

No. LobsterMail has no Google dependency at all. Your agent provisions its own inbox through the LobsterMail SDK — no Cloud Console, no service account, no Pub/Sub subscription involved.

How does LobsterMail deliver emails in real time?

LobsterMail sends an HTTP POST to your registered webhook URL when an email arrives. You register the webhook once via lm.createWebhook() and it runs until you delete it — no renewal required.

Is LobsterMail free?

The free tier is $0/month with no credit card required, and includes 1,000 emails per month. The Builder plan is $9/month and adds up to 10 inboxes and 5,000 emails per month.

Will I lose emails during the migration?

Not if you run both setups in parallel during the transition. Keep Gmail Pub/Sub running until you've confirmed LobsterMail is receiving and processing emails correctly, then decommission the old setup.

Does LobsterMail send the full email body in the webhook payload?

The webhook payload includes a 200-character preview. Use lm.getEmail(emailId) to retrieve the full body when you need it — the emailId is included in every webhook payload.

What happens if my webhook endpoint goes down temporarily?

LobsterMail retries with exponential backoff up to 10 times before auto-disabling the webhook. You can re-enable a disabled webhook via the API. Emails are not lost during retry attempts.

Does my agent's email address change when I migrate?

Yes. You'll get an @lobstermail.ai address instead of a Gmail one. Update any external services that send to the old address — everything downstream in your agent logic stays the same.

Do I need to renew anything after setup?

No. Unlike Gmail's watch subscriptions (which expire every 7 days), LobsterMail webhooks don't expire or require renewal. Register once, and it runs.

What if I'm running multiple OpenClaw agents on one Gmail account?

LobsterMail supports multiple inboxes per account. Each agent can have its own dedicated address. The Builder plan ($9/month) supports up to 10 inboxes.

Can I use a custom domain instead of @lobstermail.ai?

Custom domain support is on the roadmap. Current inboxes use the @lobstermail.ai domain.

My Gmail Pub/Sub setup is working fine right now. Is it worth switching?

If it's running without issues and you're not touching it, there's no immediate urgency. The case for switching is future maintenance: OAuth tokens break in ways you don't see coming, and the watch renewal cycle is easy to neglect until it quietly stops working. If you're starting a new agent or already debugging something, LobsterMail is simpler from day one.

Related posts