Commit Graph

5 Commits

Author SHA1 Message Date
netlas
0839fbec79 docs(leadchat): document LeadMail delivery_method fix and LeadmailDelivery patch in customization index
Some checks failed
Lock Threads / action (push) Has been cancelled
Both LeadMail-related touchpoints now logged in section B (Direct edits
to OSS files). Notes the LeadChat-owned vs upstream distinction so
future merges know which need defense and which are ours to evolve.
2026-04-27 19:57:16 +03:00
netlas
7c1c95760c docs(leadchat): add Phase 1b smoke-test checklist + LeadMail regression warning
Some checks failed
Lock Threads / action (push) Has been cancelled
Captures the test sequence to run on staging when resuming this work,
including the critical regression check that the LeadmailDelivery payload
patch hasn't broken existing transactional emails.
2026-04-27 17:03:27 +03:00
netlas
3c93714f27 feat(microsoft-shared): Phase 1b — add imap_smtp + imap_leadmail transports
Microsoft 365 Graph API requires the shared mailbox itself to be licensed
(€5/mo each), which doesn't scale across clients. Phase 1's graph_full
transport stays for licensed mailboxes; this commit adds two free-of-extra-
licensing transports alongside it. Admin picks per channel.

Three transports now:
- graph_full     -> Graph send + (Phase 2) Graph webhook receive
- imap_smtp      -> M365 xoauth2 SMTP send + xoauth2 IMAP receive
- imap_leadmail  -> LeadMail API send + xoauth2 IMAP receive

Backend:
- MicrosoftSharedConcern: SCOPES_BY_TRANSPORT map (Graph and Outlook scopes
  are different audiences — separate scope set per transport).
- AuthorizationsController accepts and validates a transport param,
  uses transport-specific scopes, encodes transport into signed state.
- CallbacksController reads transport from state, dispatches to the right
  access verifier (Graph for graph_full, new ImapAccessVerifier for imap_*),
  stores transport in provider_config, sets imap_login=upn for IMAP transports.
- New Microsoft::Shared::ImapAccessVerifier opens a Net::IMAP connection,
  authenticates XOAUTH2 with the SHARED mailbox UPN as username and the
  delegate's access token, runs CAPABILITY, closes. Confirms the SASL pattern
  works for this delegate before creating the channel.

Send routing (overlay on ConversationReplyMailerHelper):
- graph_full     -> :microsoft_shared delivery (existing Graph send service)
- imap_smtp      -> :smtp with xoauth2, delegate UPN as SASL user, channel.email
                    as From: header (Microsoft routes via Send As permission)
- imap_leadmail  -> :leadmail delivery (existing LeadmailDelivery + the small
                    extension below to forward threading headers)

Receive routing:
- New Custom::Leadchat::Inboxes::FetchImapEmailsJobExtension overlay routes
  microsoft_shared channels with imap_* transport to the existing
  Imap::MicrosoftFetchEmailService. That service already does xoauth2 IMAP
  with channel.imap_login as the SASL user; we set imap_login=upn at channel
  creation so the existing fetch logic reads the shared mailbox's INBOX with
  no service-level changes.

LeadmailDelivery: build_payload now forwards in_reply_to, references, and
message_id so conversation reply threading works on the imap_leadmail path.
LeadMail server should preserve these as RFC822 headers on the outbound MIME.

Frontend:
- MicrosoftShared.vue gets a transport radio with 3 options + per-option help.
- microsoftSharedClient already passes payload through (no change).
- en inboxMgmt.json: TRANSPORT.{IMAP_SMTP,IMAP_LEADMAIL,GRAPH}.{TITLE,HELP}.

Token management: existing Microsoft::RefreshOauthTokenService works for
all three transports — refresh tokens come back with the same scopes the
original grant had.

Phase 2 (Graph webhook receive for graph_full) remains pending; only needed
if you ship licensed-mailbox channels.
2026-04-27 15:26:09 +03:00
netlas
78cfd07009 feat(microsoft-shared): Phase 1 — OAuth + send via Graph API
Adds a new "microsoft_shared" Email Channel provider that uses Microsoft
Graph API end-to-end for sending. Bypasses xoauth2 SMTP, so it works on
tenants with Security Defaults enabled and survives the April 2026 SMTP
Basic Auth retirement.

Flow:
1. Admin picks "Microsoft Shared Inbox" in the Add Inbox wizard
2. Enters the shared mailbox UPN (e.g. sales@company.com)
3. Single OAuth round-trip as a delegate user; UPN is carried in a signed
   state parameter so the callback knows which mailbox to bind
4. Callback verifies the OAuth user has access to the UPN via
   GET /users/{upn}/mailFolders/inbox before creating the channel
5. Replies route through a custom :microsoft_shared ActionMailer delivery
   method that POSTs base64-encoded MIME to /users/{upn}/sendMail

Channel modifications use the custom/ overlay (Custom::Leadchat::*).
Direct OSS edits are wrapped in '# === LeadChat: microsoft_shared ===' markers.

Phase 2 (Graph webhook receive) and Phase 3 (re-auth, subscription
failure surfacing, channel-destroy cleanup) follow.

Azure app prerequisites (one-time, manual): add delegated permissions
Mail.Send.Shared, Mail.ReadWrite.Shared, User.Read, offline_access; grant
admin consent. No new app registration required.

See LEADCHAT.md for the full customization index.
2026-04-27 12:17:01 +03:00
netlas
800f2b2654 chore(overlay): scaffold custom/ overlay tree and add microsoft_shared? predicate
Foundation for LeadChat customizations using Chatwoot's built-in custom/
extension mechanism (ChatwootApp.extensions). Adds:

- LEADCHAT.md: index of every customization touchpoint, updated as work lands
- custom/: overlay tree where Custom::Leadchat::* modules live, autoloaded
  alongside enterprise/ via a parallel block in config/application.rb
- Channel::Email#microsoft_shared? predicate as the first overlay (used by
  the upcoming Microsoft 365 Shared Inbox provider)

OSS-file additions wrapped in '# === LeadChat: ===' markers so future
upstream-merge conflicts are mechanical.
2026-04-27 12:08:08 +03:00