Project email channels
Project email channels turn messages sent to an existing external mailbox into TOW requests. A non-encrypted project can connect up to ten Google, Microsoft, or generic IMAP mailboxes. Each mailbox routes new messages to one eligible project request type, while verified replies become customer-visible comments on the existing request.
Project admins configure channels in Project Settings → Email. Email channels are not available for end-to-end encrypted projects.
Before connecting a mailbox
Every connection needs:
- A working global outbound email transport in Admin → Server Settings → Email. Channels do not have their own SMTP credentials.
ORG_AUTH_SECRET_KEYset to a strong deployment secret. TOW encrypts OAuth tokens and IMAP credentials with this key and never returns them after saving.- An eligible request type. It must map a title or summary and cannot require fields other than summary or description.
For Google or Microsoft native access, a server administrator must configure the deployment-wide OAuth application described below. For another provider, you need its IMAP hostname, username, and password, with direct TLS on port 993 or STARTTLS on port 143.
If the project has no eligible request type, TOW creates a hidden portal request type named Emailed request. It requires a summary, allows a description and attachments, and can be selected for the channel.
POP3, delegated/shared mailboxes, secondary aliases, hosted TOW addresses, and per-mailbox SMTP are not supported. A native connection always uses the signed-in account's primary mailbox. OAuth permissions are read-only; outbound mail continues to use TOW's global transport.
Configure Google or Microsoft OAuth
Create one provider application for the TOW deployment and register the exact callback for each enabled provider:
https://tow.example.com/api/project-email/oauth/gmail_api/callback
https://tow.example.com/api/project-email/oauth/microsoft_graph/callback
The public origin must match runtime.public_app_url and should use HTTPS.
Configure these read-only delegated scopes:
- Google:
openid,email, andhttps://www.googleapis.com/auth/gmail.readonly; enable offline access. - Microsoft:
openid,profile,email,offline_access,User.Read, andMail.Readdelegated permission. Do not add application permissions.
Put the client IDs and Microsoft tenant in tow.yaml:
email:
oauth:
google:
client_id: your-google-client-id
microsoft:
client_id: your-microsoft-client-id
tenant: organizations
Put EMAIL_GOOGLE_OAUTH_CLIENT_SECRET and/or
EMAIL_MICROSOFT_OAUTH_CLIENT_SECRET in .env or the deployment secret
manager, then recreate the backend and inbound email worker. A provider appears
in the connection chooser only when its client ID, secret, and public URL are
all configured.
Connect a mailbox
- Open Project Settings → Email and choose Connect address.
- Choose Google, Microsoft, or another provider using IMAP.
- Select the request type.
- Choose where processing starts:
- New mail only starts from the setup time.
- Choose date and time accepts an exact time within the previous 30 days. TOW converts the browser's local time to UTC when it saves the channel.
- For Google or Microsoft, continue to the provider and sign in to the primary mailbox. For IMAP, enter the address, server, username, and password, test the connection, then save.
For IMAP, TOW uses INTERNALDATE, UID, and UIDVALIDITY. Native providers use
their received timestamp, immutable message identifier, and change cursor.
Provider pages are durably staged and drained oldest-first before TOW advances
the cursor, so an unordered page cannot skip mail. TOW does not trust the
message's Date header for the start boundary.
Passwords are write-only. Editing a connected channel leaves its saved password untouched unless you enter a replacement. A disconnected channel must use Reconnect to provide credentials again.
Automatic acknowledgements
Acknowledgements are enabled by default for each project. They are sent only after a new request is committed, only to the reporter, and never for a reply. The fixed subject is:
We received your request {{request.key}}
The default plain-text body is:
Hi {{requester.name}},
We received your request {{request.key}}: {{request.summary}}.
Our team will get back to you soon.
Thanks,
{{project.name}}
The body can contain only these case-sensitive placeholders:
{{request.key}}{{request.summary}}{{requester.name}}{{requester.email}}{{project.name}}{{project.key}}{{channel.address}}
Unknown or malformed placeholders are rejected, as are bodies over 10,000 characters. If the sender has no display name, requester name falls back to their email address.
Reply signatures
Each organisation member can save a personal email signature in Settings → Profile. A project admin can also set a shared signature while creating or editing an email channel. For each external email reply, TOW uses the shared channel signature when one is configured; otherwise it uses the replying agent's personal signature. Internal notes never include a signature.
Signatures can contain Markdown and only these case-sensitive placeholders:
{{agent.name}}{{agent.email}}{{project.name}}{{project.key}}{{channel.address}}
Unknown or malformed placeholders are rejected, as are signatures over 10,000 characters. TOW Markdown-escapes substituted names, addresses, and keys so their punctuation remains literal.
The composer takes a snapshot of the resolved signature when it opens and
includes it by default. An agent can use Include email signature to include
or omit that snapshot for the current reply without changing the saved
personal or shared template. A signature cannot be sent without an authored
reply body. When sent, the signature is separated from the body with the
standard -- email signature delimiter.
The resolved signature becomes part of the shared ticket comment and outgoing email, but the staff conversation view hides it from outbound agent message bubbles. Changing or deleting a template does not rewrite historical comments, and delivered email cannot be recalled. Account erasure clears the member's saved personal template, while historical shared prose follows the same retention policy as other ticket comments.
Requests, participants, and attachments
For a new message, TOW uses the decoded subject as the summary and the plain-text body as the description. When plain text is absent, it converts a sanitized HTML body to text.
The sender becomes an organisation-scoped portal customer and the request
reporter. This does not grant portal login. Valid external recipients in
To and Cc become request participants, up to 50 per request. TOW excludes
organisation members from the participant list, along with connected channel
addresses, the global sender and reply-to address, and configured hosted
addresses. Organisation members can still create requests by emailing the
connected address; being an organisation member does not grant the resulting
portal customer a portal login.
Agents with service-agent permission can also manage participants from the ticket conversation. Use Add CC to add an active external customer by email, or remove an existing participant from the Participants list. The reporter is fixed and does not count toward the 50-participant limit. Adding a participant does not send an invitation or a copy of earlier mail; they begin receiving the next external reply. A removed participant keeps their organisation-scoped customer record but loses request access and is excluded from future replies.
Every CC receives every customer-facing reply on the request. Until side conversations are available, use a separate mailbox for correspondence that should remain between staff and a vendor.
TOW imports up to five safe attachments within the configured upload limit. Email attachments on new requests and customer replies are marked as email-originated and quarantined for normal media processing. Dangerous or oversized parts are logged and skipped without discarding the request or reply.
Replies and privacy
Staff comments on email requests default to Reply to customer. Choose Internal note to keep a comment private.
An external comment sends one separate email to each active reporter and
participant, avoiding recipient disclosure. The subject is
Re: [KEY] Summary, the connected address is set as Reply-To, and TOW
preserves RFC message threading. TOW includes a stable identifier in
References as well as Message-ID, so replies remain attachable when an SMTP
relay replaces the message's Message-ID. Editing an unsent comment refreshes
its pending emails; deleting it cancels pending emails. Already sent mail is
not recalled or resent. Removing a participant changes future fan-out only; it
does not cancel email that is already queued or sent.
Inbound replies attach only when In-Reply-To or References identifies a
message recorded for the same channel and the sender is the reporter or an
active participant. TOW never threads by subject or ticket key. An unknown
reference creates a new request; an unauthorised sender on a recognised thread
is rejected without exposing ticket information.
TOW ignores its own generated messages, bounces, mailing-list or bulk traffic, and auto-submitted mail. Customer email replies notify internal watchers but do not send the reply back into the customer thread.
Health, logs, and incidents
The connected-address table shows health, last successful connection, and last received time. Open Health and logs for recent redacted channel events. Logs never contain OAuth tokens, IMAP credentials, provider message IDs, or raw MIME.
The inbound worker polls every 5 seconds by default. Failed connections use exponential backoff. After three consecutive connection failures, all active project managers receive one incident through both the in-app inbox and global email. A successful connection closes the incident latch. A terminal per-message failure notifies managers immediately and does not block later messages. If a provider revokes authorization or refresh fails permanently, the channel shows Reconnect required instead of retrying indefinitely.
Pause, disconnect, and reconnect
Pausing keeps credentials and thread history but stops inbound polling. Staff can continue replying to existing requests through the global outbound email transport. Resume when the mailbox is ready to receive messages again.
Disconnecting permanently scrubs the saved credentials and stops inbound mail and staff customer replies. Existing requests, comments, thread mappings, and audit logs remain. Reconnecting the same channel with new credentials or provider sign-in restores the preserved mappings. A native channel requires signing in to the same provider account; TOW rejects a different mailbox.
Requests created by email cannot be moved to another project. A request type also cannot be archived while an active email channel references it.
Private mailservers
For server-side request-forgery protection, TOW rejects IMAP destinations that resolve to private, loopback, link-local, multicast, reserved, or unspecified addresses. To connect an intentionally private self-hosted mailserver, add its exact hostname or IP to:
email:
inbound:
allowed_hosts:
- imap.internal.example
Restart the backend and inbound email worker after changing runtime configuration. Allowlist entries must match the exact hostname or IP address; wildcards are not accepted.