Skip to content

Receive email over IMAP

Not every self-hosted deployment can expose a public webhook endpoint for inbound email. IMAP polling gets you the same result (visitor replies land as conversation messages) by having Quackback poll a mailbox instead of a provider pushing to you.

This page covers the self-hosted IMAP transport. For the concepts behind the email channel (threading, agent replies, routing) see Email channel.

IMAP vs. the provider webhook

Quackback supports two ways to receive inbound email:

Provider webhookIMAP polling
SetupConfigure a provider (e.g. Resend inbound) and point its webhook at your instancePoint Quackback at any mailbox you already control
RequiresA public HTTPS endpoint reachable from the providerOutbound access to your IMAP host only
LatencyNear-instantUp to ~60 seconds (poll interval)

If your instance isn't publicly reachable, or you already have a support mailbox and don't want to route it through a third-party inbound-email provider, use IMAP.

Configure the poller

Set these variables and restart:

EMAIL_INBOUND_PROVIDER=imap
IMAP_HOST=imap.example.com
IMAP_PORT=993
IMAP_USER=support@example.com
IMAP_PASSWORD=your-mailbox-password
IMAP_TLS=true
IMAP_MAILBOX=INBOX
VariableDefaultNotes
EMAIL_INBOUND_PROVIDERunsetMust be imap to enable the poller
IMAP_HOSTrequiredNo default
IMAP_PORT993 (TLS) or 143 (plaintext)
IMAP_USERrequiredNo default
IMAP_PASSWORDrequiredNo default
IMAP_TLStrueSet to false for a plaintext connection
IMAP_MAILBOXINBOXMailbox to poll

EMAIL_INBOUND_PROVIDER, IMAP_HOST, IMAP_USER, and IMAP_PASSWORD are all required together. Leave any one unset and the poller never connects. There's no error, it just stays off.

How it works

A background worker polls the mailbox for unseen messages roughly every 60 seconds, parses each one, and creates or threads it into a conversation. Messages that ingest successfully, or are deliberately dropped as spam or unroutable, are marked seen. A message that fails to ingest (a transient error) is left unseen so the next poll retries it.

The poller only runs on a replica where QUACKBACK_ROLE is worker or all. If you've split web and worker replicas, make sure a worker replica is running or inbound mail never gets picked up.

Replies from your team route back to the visitor by matching the In-Reply-To/References threading chain. If you also configure EMAIL_INBOUND_DOMAIN and EMAIL_INBOUND_SIGNING_SECRET for the webhook path, replies additionally route by plus-address. The two inbound methods aren't mutually exclusive.

Verify it works

Send a test email to the configured mailbox, then check that it appears as a new conversation within about a minute. If it doesn't:

  1. Confirm QUACKBACK_ROLE isn't web on every replica
  2. Check the logs for imap inbound not configured (means a required variable is missing) or a connection error
  3. Confirm the conversations channel is enabled in Admin > Settings > Channels

Next steps