Open source · MIT · Build an AI front desk, part 3
email-kit
Email: send once, retry safely, read the address back. Retries, double-clicks and bot tool-calls all try to send the same email twice. How to make that impossible, and how a voice bot gets an address right.
- TypeScript
- Resend
Early (v0.x), written with Claude Code and directed and reviewed by me. Not on npm yet: clone the repository to use it.
"Email me the details" is the most requested thing a phone or chat agent does, and the easiest to get wrong in quiet ways: the same email delivered twice because a request retried, an email to someone who unsubscribed, or a message sent to an address the bot misheard.
- Your code
- Validate and check suppression
- Idempotency key
- Provider
- Retry only if retryable
Check before you send
Every send validates the address, requires some content, and asks a suppression list whether the recipient unsubscribed or bounced. If so, it refuses before the provider is ever called.
Make a second send impossible
Each message gets an idempotency key derived from the recipient, subject and body. The key goes to the provider, and a repeat returns the first result instead of delivering again. If identical content can legitimately be sent twice (say, two orders), pass a scope such as an order id so they get different keys.
Retry only what says it is retryable
A temporary 503 should be retried with exponential backoff and a little random jitter; a rejected address should not. Providers signal which is which, and unknown errors are treated as permanent.
import { createMailer } from '@27colab/email-kit';
import { FakeProvider } from '@27colab/email-kit/testing';
const provider = new FakeProvider().failNext(2);
const mailer = createMailer({ provider, from: 'Acme <hello@example.test>', retry: { attempts: 3 } });
await mailer.send({ to: 'jane@example.com', subject: 'Your quote', text: 'Hi!' });
console.log(provider.calls, provider.outbox.length); // 3 1Getting an address from a voice call
Callers say "jane dot doe at example dot com" or, in Spanish, "jane punto doe arroba example punto com". The parser turns that into an address, or returns nothing so the bot asks again. The bot then reads the address back, letter by letter, and only sends after a yes, only to the address the caller gave for themselves, and at most once per request.
Try to break it
Dictate an address, confirm it, then make the provider fail, press send twice, or unsubscribe the address.
Email me this: read it back, send it once
A caller dictates an address. The agent parses it, reads it back, and sends only after a yes. Then break it: make the email provider fail, click send twice, or unsubscribe the address. Real email-kit (opens in a new tab) code with a fake provider; no email is sent anywhere.
What happened
- Press “Understand it” to start.
Provider outbox
Provider calls so far: 0 · Emails actually delivered: 0
What this does not do
- It is not a replacement for Nodemailer, React Email or a provider SDK: no SMTP, no MJML, no queue, no inbound parsing.
- It has one real provider (Resend over plain fetch); another is one class implementing the provider interface.
- Pre-1.0 and not audited for production use. In this demo's browser copy, the idempotency hash is a non-cryptographic stand-in.
Get it
git clone https://github.com/27colab/email-kit.git
cd email-kit && npm ci && npm testUsed in
Want this built into your product? Get in touch.