Skip to content

Security: pantalytics/pan_mail_pro

Security

docs/security.md

Security

Mail Pro is designed with security as a priority, following the principle of least privilege.

Authentication

Three providers, two kinds of credential:

Provider Credential Who holds it
Microsoft 365 OAuth 2.0, delegated permissions only Each user signs in; a shared address is sent as with the user's own token
Google Workspace OAuth 2.0, delegated permissions only Each user signs in; a shared address is its own Workspace account, authorized once
IMAP/SMTP Server, login and password Entered by an administrator, per address

OAuth 2.0 with Delegated Permissions

On Microsoft 365 and Google Workspace the app acts on behalf of the signed-in user, never as an administrator.

Aspect Implementation
Protocol OAuth 2.0 Authorization Code Flow
Identity Provider Microsoft Entra ID (Azure AD) or Google
Permission Type Delegated only
Token Lifetime Access: 1 hour, Refresh: provider policy (Microsoft: 90 days of inactivity)

Required Permissions

Microsoft 365

Personal mailbox:

Permission Purpose
Mail.ReadWrite Create drafts, read emails
Mail.Send Send emails
offline_access Obtain refresh tokens
User.Read Read user profile for identification

Shared mailbox (additional):

Permission Purpose
Mail.ReadWrite.Shared Create drafts in shared mailbox
Mail.Send.Shared Send from shared mailbox

Note: All permissions are delegated. Users authorize their own accounts.

Google Workspace

Scope Purpose
openid Identifies the user during the callback
email Reads the address that just signed in
https://www.googleapis.com/auth/gmail.modify Read incoming mail and label it
https://www.googleapis.com/auth/gmail.send Send mail

gmail.modify and gmail.send are restricted scopes. Mail Pro never asks for https://mail.google.com/ (full mailbox control), because it never deletes anything. A shared address is its own Workspace account and grants the same scopes once, for itself.

IMAP/SMTP

No scopes and no consent screen. The account holds the server names, a login and a password, and can do whatever that login can do on that server.

Token Security

Encryption at Rest

Every credential the module holds, OAuth access and refresh tokens, IMAP/SMTP passwords, and the provider's own client secret, is encrypted before storage:

  • Algorithm: Fernet (AES-128-CBC with HMAC)
  • Key: A random 32-byte key generated on first use and stored in ir.config_parameter under pan_mail_pro.encryption_key (renamed from x_pan_outlook_pro.encryption_key by the 19.0.6.0.0 migration; the code still adopts a key found under the old name rather than minting a new one)
  • Storage: Encrypted in PostgreSQL

Key and ciphertext live in the same database. A database dump therefore contains both, which makes any backup of this database credential material and means it must be handled to the same standard as the tokens themselves. Restoring a production dump into a test environment carries working OAuth tokens with it; revoke or clear pan.mail.account rows after such a restore.

An earlier version of this document stated the key was derived from the Odoo database UUID. That was never what the code did (models/encryption_utils.py), and derivation from a value stored in the same database would not have changed the property above.

For deployments that need the key held outside the database, set the PAN_MAIL_ENCRYPTION_KEY environment variable; when present it takes precedence over the stored parameter and nothing is written to ir.config_parameter.

Token Handling

  • Access tokens are short-lived (1 hour) and refreshed automatically
  • A refresh token is replaced when the provider issues a new one; Google usually does not, so the stored one is kept
  • Tokens are never logged or exposed in error messages
  • Tokens are cleared on disconnect, and removed altogether when the database is neutralized (a staging or test copy)

Shared Mailbox Access

  • Microsoft 365: each user authenticates with their own account and needs SendAs permission on the shared address. No shared credentials.
  • Google Workspace: the shared address is its own Workspace account, authorized once by an administrator. Its refresh token is stored like any other, with no Odoo user attached.
  • IMAP/SMTP: the address's login and password, entered by an administrator and stored encrypted.

Data Flow

User → Odoo → Microsoft Graph API / Gmail API / IMAP+SMTP host
         ↑
   credential
   (encrypted)
  1. User initiates action in Odoo
  2. Odoo retrieves the encrypted credential
  3. Credential decrypted in memory
  4. Call made to the provider
  5. Response processed in Odoo

The one exception is the daily heartbeat to app.mailpro.pantalytics.com, the whole of which is: the database id, the Mail Pro and Odoo version, how many accounts are connected, whether sync is healthy, and the last 24 hours of link coverage as counts and rule names; plus the Odoo URL once, when the instance is connected, so the approval page can name it. Never an address, a subject, a body or a name. With Help improve Mail Pro switched on for your workspace, the browser also sends named events and a masked recording of the Mail Pro inbox to the same host; every word, field and attribute is masked before it leaves the browser, and the check that proves it runs on every release. See Connect to Pantalytics.

Audit Trail

All email operations are logged:

  • Sent emails indexed by the Message-ID the provider put on the wire
  • Sending logged with the [Outgoing Mail] tag, sync with [Incoming Mail]
  • Provider API errors logged with [Graph API], [Gmail API], [IMAP] or [SMTP]

Compliance

  • GDPR: User data processed per the provider's data processing terms
  • Data residency: Determined by the provider's tenant configuration
  • Odoo data: Stored in your Odoo database location

There aren't any published security advisories