Tendkit

Search documentation

Find a docs page

Get Started

SMTP and IMAP

Any mailbox: you bring the SMTP transport and IMAP poller for your runtime.

Install

Terminal
npx shadcn@latest add @tendkit/channel-smtp

It lands in lib/support/channels/. Import smtpChannel from there.

Set up

  1. Pick your network libraries

    The adapter builds and parses MIME; you inject two functions: smtp.send(raw, envelope) and imap.fetchSince(state). On Node, nodemailer and imapflow work well. On Cloudflare Workers use port 587 or 465 (25 is blocked), with nodemailer or worker-mailer for SMTP and imapflow for IMAP.

  2. Track position by UID

    Store the mailbox's UIDVALIDITY and next UID in the returned state. On the first call return no messages, only the current position, so old mail isn't imported.

  3. Run the schedule

    runScheduled() calls your IMAP poller. Keep each run short; return at most a batch of messages.

Configure

lib/support/index.ts
smtpChannel({
  id: "email",
  address: "support@acme.com",
  smtp: {
    send: (raw, envelope) =>
      transporter.sendMail({ raw: Buffer.from(raw), envelope }).then(() => {}),
  },
  imap: { fetchSince: (state) => pollInbox(state) },
})

Options

NameTypeDescription
id*stringStable channel id, stored on every ticket and used in the webhook URL. Never change it.
address*stringThe address customers write to and replies come from.
smtp*{ send(raw, envelope) }Delivers one complete RFC 5322 message.
imap{ fetchSince(state) }Reads the inbox. Leave out when mail arrives another way.
replyAddressstringAn address that routes back to this mailbox, for the ticket token.

Behaviour

  • Works with Fastmail, Zoho, cPanel hosting, or Gmail and Microsoft 365 with an app password.