Skip to content

Gmail Provider

Use the Gmail provider when you want MailAtlas to receive messages from a Gmail mailbox or send from a personal Gmail address or Gmail-configured send-as alias.

MailAtlas uses the Gmail API with OAuth. mailatlas auth gmail is send-focused by default for compatibility, but you can request receive or combined send/receive capabilities explicitly.

This is the recommended Gmail path. Gmail SMTP app passwords can still work through --provider smtp for outbound mail, but they are a compatibility option for local testing, not the preferred Gmail integration.

Use mailatlas auth gmail when a local operator wants to authorize Gmail once and reuse that local token for CLI receive or send commands.

With mailatlas[keychain] installed, MailAtlas stores token material in the operating system keychain by default. Without the keychain extra, it falls back to a user config token file outside the MailAtlas workspace.

Backend applications should not rely on the local CLI token store. Store Gmail refresh tokens in your own encrypted credential store, refresh them in your backend, and pass short-lived access tokens to MailAtlas at receive or send time with gmail_access_token or MAILATLAS_GMAIL_ACCESS_TOKEN.

You need:

  • A Google Cloud project.
  • Gmail API enabled for that project.
  • A Google OAuth desktop client ID.
  • A Google OAuth client secret if Google issued one for that client.
  • The Gmail address you want to receive from or send from.

In Google Cloud Console:

  1. Create or select a Google Cloud project.
  2. Enable the Gmail API for that project.
  3. Configure the OAuth consent screen.
  4. For a personal Gmail test, choose an external app and add your Gmail address as a test user while the app is in testing mode.
  5. Open APIs & Services, then Credentials.
  6. Create an OAuth client ID with application type Desktop app.
  7. Copy the client ID and client secret.

Send-only auth is the default:

Terminal window
python -m pip install "mailatlas[keychain]"
mailatlas auth gmail \
--client-id "$MAILATLAS_GMAIL_CLIENT_ID" \
--client-secret "$MAILATLAS_GMAIL_CLIENT_SECRET" \

MailAtlas opens a browser unless --no-browser is passed, asks Google for the gmail.send scope by default, receives the OAuth callback on 127.0.0.1, and stores the resulting token outside the MailAtlas workspace.

Receive-only auth asks for the read-only Gmail scope:

Terminal window
mailatlas auth gmail \
--client-id "$MAILATLAS_GMAIL_CLIENT_ID" \
--client-secret "$MAILATLAS_GMAIL_CLIENT_SECRET" \
--capability receive

Use one token for both local receive and send:

Terminal window
mailatlas auth gmail \
--client-id "$MAILATLAS_GMAIL_CLIENT_ID" \
--client-secret "$MAILATLAS_GMAIL_CLIENT_SECRET" \
--capability send,receive

Capability scopes:

CapabilityGmail scope
sendhttps://www.googleapis.com/auth/gmail.send
receivehttps://www.googleapis.com/auth/gmail.readonly

MailAtlas does not write Gmail OAuth tokens to store.db, raw snapshots, logs, or JSON receive/send results.

Check local status:

Terminal window
mailatlas auth status gmail

Remove local Gmail auth:

Terminal window
mailatlas auth logout gmail

Run one bounded receive pass:

Terminal window
mailatlas receive \
--provider gmail \
--label INBOX \
--limit 50

Receive uses the Gmail API, decodes raw messages into RFC 2822 bytes, and stores them as regular MailAtlas documents under the local workspace. Provider metadata records Gmail message ID, thread ID, label IDs, history ID, internal date, and local receive account ID.

Receive is read-only. MailAtlas does not mark Gmail messages read, archive them, delete them, or change labels.

Use a Gmail search query when label-only receive is not precise enough:

Terminal window
mailatlas receive \
--query 'newer_than:7d' \
--limit 25

Run foreground polling:

Terminal window
mailatlas receive watch \
--provider gmail \
--label INBOX \
--interval 60

Inspect local receive state:

Terminal window
mailatlas receive status

The status output includes configured receive accounts, cursor state, recent runs, and the last error.

Terminal window
mailatlas send \
--provider gmail \
--subject "MailAtlas Gmail API test" \
--text "Sent with Gmail API OAuth."

Use --idempotency-key when repeating tests so retries return the existing outbound record instead of sending another message:

Terminal window
mailatlas send \
--provider gmail \
--subject "MailAtlas Gmail API test" \
--text "Sent with Gmail API OAuth." \
--idempotency-key gmail-api-test-1

For local CLI usage, prefer the operating system keychain:

Terminal window
python -m pip install "mailatlas[keychain]"
mailatlas auth gmail \
--client-id "$MAILATLAS_GMAIL_CLIENT_ID" \
--client-secret "$MAILATLAS_GMAIL_CLIENT_SECRET" \
--token-store keychain

--token-store auto is the default. It uses keychain storage when the optional dependency is available, then falls back to a token file.

Without keychain storage, MailAtlas stores Gmail OAuth tokens outside the workspace:

PlatformDefault token file
macOS~/Library/Application Support/MailAtlas/gmail-token.json
Linux and other Unix-like systems~/.config/mailatlas/gmail-token.json

Force file storage:

Terminal window
mailatlas auth gmail \
--client-id "$MAILATLAS_GMAIL_CLIENT_ID" \
--client-secret "$MAILATLAS_GMAIL_CLIENT_SECRET" \
--token-store file

Use an explicit token path for tests:

Terminal window
mailatlas auth gmail \
--client-id "$MAILATLAS_GMAIL_CLIENT_ID" \
--client-secret "$MAILATLAS_GMAIL_CLIENT_SECRET" \
--token-file /tmp/mailatlas-gmail-token.json

Then send with that token file:

Terminal window
mailatlas send \
--provider gmail \
--gmail-token-file /tmp/mailatlas-gmail-token.json \
--subject "MailAtlas Gmail token-file test" \
--text "Sent with a test token file."

Receive with that token file:

Terminal window
mailatlas receive \
--token-file /tmp/mailatlas-gmail-token.json \
--label INBOX \
--limit 10

--token-file and --gmail-token-file always use the explicit file path. This keeps throwaway local tests easy to inspect and delete.

MAILATLAS_GMAIL_TOKEN_FILE also selects a file store when no token store is passed explicitly.

Backend applications should:

  1. Store Gmail refresh tokens in their own encrypted credential store.
  2. Refresh tokens in the backend.
  3. Pass a short-lived access token to MailAtlas.
  4. Avoid relying on the local CLI token store.

Python example:

from mailatlas import MailAtlas, OutboundMessage, ReceiveConfig, SendConfig
atlas = MailAtlas()
receive_result = atlas.receive(
ReceiveConfig(
gmail_access_token="ya29...",
gmail_label="INBOX",
limit=50,
)
)
result = atlas.send_email(
OutboundMessage(
from_email="[email protected]",
subject="Gmail API test",
text="Sent with a backend-managed access token.",
),
SendConfig(
provider="gmail",
gmail_access_token="ya29...",
),
)

MailAtlas keeps local outbound raw snapshots free of Bcc headers.

Gmail API sends use a provider-only transient MIME payload that includes BCC for Gmail delivery while preserving the Bcc-free local audit snapshot.

Confirm --client-id is set or MAILATLAS_GMAIL_CLIENT_ID is exported.

Use an OAuth desktop client and rerun mailatlas auth gmail.

--token-store keychain fails before auth starts

Section titled “--token-store keychain fails before auth starts”

Install mailatlas[keychain] or use --token-store file for a local test.

Use the authenticated Gmail address or a Gmail send-as alias configured in Gmail.

Receive fails because the token is send-only

Section titled “Receive fails because the token is send-only”

Run mailatlas auth gmail --capability receive or mailatlas auth gmail --capability send,receive, then try mailatlas receive again.

Gmail no longer accepts the stored history cursor. Run an explicit full sync:

Terminal window
mailatlas receive --label INBOX --limit 50 --full-sync

After moving to Gmail API OAuth, revoke old app passwords that are no longer needed.