Complete Microsoft 365, Google Workspace and IMAP/SMTP email integration for Odoo - send and receive with full control.
Outgoing Email:
- Send From dropdown in email composer
- Personal, shared, and notification mailbox support
- Auto-create personal mailbox when you connect your account
- Default mailbox per user
- One sender per mail, chosen once: a mail that cannot be sent from the mailbox you picked fails and says why, rather than leaving from a different address
Providers:
- Microsoft 365 (Graph API, OAuth 2.0)
- Google Workspace (Gmail API, OAuth 2.0)
- Any IMAP/SMTP mailbox - Soverin, Fastmail, your own server - with a server, a login and a password
Incoming Email:
- Automatic sync from every configured mailbox (1 min interval)
- 2-way sync: Inbox and Sent Items
- Reply threading: our own headers, then the References chain, then the provider's thread id, then subject and participants as a suggestion
- Historical email sync with configurable start date
- Known partners filter: only sync email from existing contacts, or from anyone, creating contacts as needed
- Per-contact block list to exclude specific senders
- Route a mailbox to a team alias so new email creates a lead or a ticket instead of landing on the sender's contact
Security:
- OAuth 2.0 with delegated permissions only (least privilege)
- Token encryption at rest
Create a Pantalytics account at
app.mailpro.pantalytics.com/start
(free up to 100 mails a day per Odoo instance), then add the module, branch
19.0, to your Odoo. The full guide per host is
docs/getting-started/installation.md.
Odoo.sh: Settings → Submodules → git@github.com:pantalytics/pan_mail_pro.git,
or from your repository:
git submodule add -b 19.0 https://github.com/pantalytics/pan_mail_pro addons/pan_mail_pro
git commit -m "Add pan_mail_pro" && git pushCloudpepper: your instance → Modules → Git → add
https://github.com/pantalytics/pan_mail_pro, branch 19.0, restart.
Your own server or Docker: git clone -b 19.0 https://github.com/pantalytics/pan_mail_pro into a folder on addons_path,
pip install cryptography, restart Odoo.
Then Apps → Update Apps List → Mail Pro → Install on every host.
After installing the module, go to Settings → scroll to Mail Pro and press Connect to Pantalytics (see docs/getting-started/connect-pantalytics.md).
The page is then a checklist of three steps; the arrow on each line opens the table where it is answered:
- Email provider - where your mail is hosted (Microsoft 365, Google Workspace or IMAP/SMTP), with the app registration or OAuth client that goes with it. The redirect URI to paste back into the provider's console is shown on that form. IMAP/SMTP has no global credential; see below.
- Internal domains - your own email domains. Required: no mailbox can sync until this is answered. Odoo suggests them from your mailboxes, company email and alias domains.
- Mailboxes - create the first mailbox, tick it as the notification mailbox, and configure sending and incoming sync.
Below the checklist, Users shows who has connected a mailbox and invites the rest. A database runs on one provider; switching means editing that row, and the provider's console issues a new client secret for it.
You can invite users before any of this is finished. Mail Pro leaves SMTP alone until the first mailbox exists, and once it does, invitations and password resets wait in the queue until step 3 is done rather than being dropped.
An IMAP mailbox has no consent screen, so its credentials are typed in once:
- Go to Settings → Technical → Email → Mail Pro → Email Accounts and create an account.
- Set Provider to IMAP / SMTP and fill in the address. Known hosters (Soverin) fill in their own servers; anything else is typed in.
- Enter the IMAP and SMTP servers, the login (defaults to the address) and the password, then press Test Connection - both halves are checked, because a mailbox that reads but cannot send is broken.
- Leave Odoo User empty for a shared address such as
info@; set it for a person's own mailbox. - Create the mailbox under Settings → Technical → Email → Mail Pro → Mailboxes with the same address and provider IMAP / SMTP.
The Sent folder is detected from the server (\Sent), and can be overridden on
the account when a server names it something unusual. Mail sent from Odoo is
filed there, so it shows up in your own mail client too.
- Go to My Preferences → Mail Pro
- Click Connect Mailbox
- Sign in and grant permissions
- A personal mailbox is created for the address you signed in with, and set as your Send from
An admin can also send everybody the invitation with Send Mail Pro Invite on the Users list (Settings → Mail Pro → Users); the link in it drops each user straight on the consent screen.
Until you connect, a banner sits above every screen with a button that goes straight to the consent screen. It is only shown where that button would work: an internal user, a provider that has a consent screen, and not on a staging copy. Once connected, Send Test Email on My Preferences → Mail Pro proves the address really sends. Every mailbox form has the same button.
Note: until your account is connected and a Send from mailbox is set, the email composer shows a warning banner saying so.
Go to Settings → Technical → Email → Mail Pro → Mailboxes (the arrow on step 3 of the checklist)
The type is not a setting. It follows from the owner:
| Type | Description |
|---|---|
| Personal | The owner's own address. Created when they connect. Only visible to the owner. |
| Shared | Any address that is not its owner's own, or has no owner (sales@, support@). Visible to all users. On Microsoft 365 each user sends with their own OAuth grant; on Gmail and IMAP the address has credentials of its own. |
On Microsoft 365 a shared mailbox that reads mail still names an Owner: the person whose grant reads it. That does not make it theirs.
Exactly one mailbox also has Notification Mailbox ticked: system emails — user invitations, password resets, activity reminders — go out from it, using its owner's credentials. Tick it straight from the mailbox list; to move it, untick the current one first.
Prerequisite: one mailbox must have Notification Mailbox ticked (required for handling emails from external authors).
Replies to email sent from Odoo always land on the record they answer. That needs no setting. Sending needs none either: which mailbox an email leaves from is picked per message, under Send From in the composer, and it shows up in the Sent Items of your mail app like any other mail.
-
Open a mailbox, tab Sync Settings
-
Pick a Sync level. Each one keeps strictly more than the one above it:
Level What is read back Replies, in Odoo only (default) Only replies to mail Odoo sent Replies, in Odoo and your mail app Also your own replies, read back from the Sent folder Replies and new email, existing contacts only Also new conversations started by people who are already contacts Replies and new email, everyone Also new conversations from strangers, who become contacts. Newsletters and private email included, so pick it only for an address that exists to hear from strangers Under the choice the form shows what happens in Odoo for each situation: a reply from your contact, your reply from your mail app, new mail from your contact, new mail from your mail app, new mail from a stranger. Mail you start from your own mail app never enters, whatever the level: only your replies do.
-
From the third level on, optionally route new conversations to a team (alias) so they create tickets or leads instead of landing on the sender's contact
-
On the Setup tab: the Type, the Owner (a user with a connected account), and optionally Import from for historical email
-
Save
Sync behavior:
- Internal domains must be configured in Settings → Mail Pro before any mailbox can sync. Add one tag per domain; Odoo suggests them from your mailboxes, company email and alias domains. Email between those domains is never synced.
- There is no way to switch this off, globally or per mailbox. A mail with any outside recipient is correspondence and is still logged, so "internal" means every party is one of your own domains
- Emails sync automatically every minute
- Set a sync start date to import historical emails (default: sync from now)
Per-contact block list:
- Go to a contact's form view → Email Sync tab
- Enable "Block Email Sync" to exclude that contact from all mailbox sync
Four rules run strongest-first and stop at the first confident answer: our own
X-Odoo-* headers, the References chain, the provider's thread id
(conversationId, threadId, or the root of the References chain on IMAP), and
finally subject plus participants, which never acts alone.
Open the mail's row under Settings → Technical → Email → Mail Pro → Mail Routing: it records the rule that placed it and every candidate it rejected. The usual cause is that the original message was never synced, so there was nothing to thread onto — set an earlier Import from on the mailbox.
- Check Settings → Technical → Scheduled Actions → "Mail Pro: Fetch Incoming Mail"
- Verify the mailbox's Sync level includes new email if the mail you are missing is not a reply
- Verify the mailbox has usable credentials — its Status column says so
- Check logs for
[Incoming Mail]entries
No mailbox has usable credentials. The account behind each one is not connected.
That is deliberate. If the chosen mailbox cannot send, you get an error naming
what to fix, and the mail waits in Settings → Technical → Email → Emails with
the same reason on it — rather than going out from notifications@ and looking
like it worked. Other emails sent at the same time are unaffected.
User lacks SendAs permission on the mailbox in Microsoft 365. Configure this in Exchange Admin Center.
On Microsoft 365 and Google Workspace the module uses delegated permissions only - the app acts on behalf of the signed-in user, never as an administrator. IMAP/SMTP has no such concept: the account is a login and a password, entered by an administrator.
| Aspect | Implementation |
|---|---|
| Authentication | OAuth 2.0 with Microsoft Entra ID or Google; server login and password on IMAP/SMTP |
| Permissions | Delegated only, where the provider offers it (no admin access) |
| Credential storage | Encrypted at rest (Fernet) — tokens, passwords and the client secret |
| Shared mailbox | Microsoft 365: SendAs on the address. Gmail and IMAP/SMTP: its own credentials |
See ARCHITECTURE.md for technical details.
Once mail is flowing, three screens under Settings → Technical → Email → Mail Pro tell you whether it is going where you expect:
| Screen | Question it answers |
|---|---|
| All Communication | Every mail, with the document it landed on |
| Link Coverage | How much of it lands on a document at all |
| Mail Routing | Which rule placed each mail, and what it rejected |
The Mail Routing log flags two cases for review: mail that fell back to a contact's chatter (delivered, but nobody is looking there), and mail that created a new record while other candidates existed (possibly a duplicate ticket for a conversation already running). Threaded mail never flags — a review queue that cries wolf gets ignored.
| Document | Contents |
|---|---|
| ARCHITECTURE.md | The design: models, seams, flows, and why. Single source of truth |
| CLAUDE.md | Workflow: environments, commands, CI, Odoo traps |
| DESIGN_SYSTEM.md | UI conventions for the settings and mailbox screens |
| TESTPLAN.md | Manual test plan for what CI cannot reach |
cd .local
docker-compose stop odoo
docker-compose run --rm odoo python -m odoo -c /etc/odoo/odoo.conf \
-d test_db -u pan_mail_pro --test-enable --test-tags=pan_mail_pro --stop-after-init
docker-compose start odoo41 test files cover five areas: the provider contract, each provider's wire behaviour, the incoming pipeline (fetch → filter → match → post), sending, threading, the composer and onboarding, and the migration scripts. See ARCHITECTURE.md §12.
Mail Pro is source-available under the Elastic License 2.0, the same licence as Odoo MCP Pro. In short: read the code, run it, modify it for your own use. You may not offer it to third parties as a hosted or managed service, and you may not remove or circumvent its licensing notices.
Releases up to and including v19.0.7.13.1 were published under LGPL-3 and
stay under LGPL-3. The relicence applies from 19.0.7.14.0 onwards.
Mail Pro is sold direct, not through the Odoo Apps store, which requires
OPL-1 for paid apps. See ARCHITECTURE.md §9.16 for why.
Commercial terms and support: support@pantalytics.com.