DEV Community

Kumar Deepanshu
Kumar Deepanshu

Posted on Originally published at lumbox.co

Durable Email Workflows with Temporal and Lumbox

Originally published at lumbox.co

Temporal solves the problem every async workflow eventually hits: what happens if the process dies mid-flow? For email, it's acute — you kick off a signup, the worker crashes, and now you have a Lumbox inbox waiting for an OTP that no one is listening for. Temporal activities make that durable.

The pattern: inbox creation as an activity

import { proxyActivities } from "@temporalio/workflow";
import type * as activities from "./activities";

const { createInbox, submitSignup, waitForOtp, submitOtp } =
  proxyActivities<typeof activities>({
    startToCloseTimeout: "5 minutes",
  });

export async function signupWorkflow(service: string, user: User) {
  const inbox = await createInbox(`signup-${service}`);
  await submitSignup(service, user, inbox.address);
  const otp = await waitForOtp(inbox.id, 120);
  await submitOtp(service, otp);
  return { success: true, address: inbox.address };
}
Enter fullscreen mode Exit fullscreen mode

Long waits are fine

Some verification flows send a link that expires in 24 hours. Temporal can hold a workflow open for days with no resource cost — when the worker comes back, the state picks up. Lumbox inboxes don't expire unless you tell them to, so a workflow that sleeps for a day and then checks the inbox works exactly as expected.

Retries are automatic

If waitForOtp times out, Temporal retries per your activity policy. Lumbox's timeout is server-side — the HTTP call cleanly returns after the timeout window, and Temporal handles the rest. lumbox.co.

Top comments (0)