Skip to main content

Email audit via Gmail labels

Every email FinMatch sends through SendGrid carries a self-copy BCC to a plus-addressed alias of the From mailbox. A Gmail filter on each From mailbox routes the self-copy to a dedicated Sent (audit) label, giving us a searchable audit trail without standing up any new infrastructure.

This is the only audit channel for FinMatch outbound mail right now. The admin Emails page (/emails) shows what gets sent; the Gmail label shows the actual sent copy — useful for verifying delivery, message formatting, and timing.

How it works

SendGrid sends from FinMatch's MTAs, which means outbound mail does not appear in the Sent folder of the From Gmail account — Google only sees a mail in Sent when Google itself sent it. The plus-addressing trick (address+tag@domain) routes a copy back to the same mailbox via BCC; Google then accepts that copy on inbound and a filter labels it.

+----------------------+         +-----------+         +----------------------+
| merchant-api or | send | SendGrid | deliver | recipient inbox |
| finance-assistant |-------->| |-------->| (merchant contact |
+----------------------+ +-----+-----+ | or james@...) |
| +----------------------+
| bcc
v
+-----------+
| Gmail of |
| the From |
| mailbox |
+-----+-----+
|
v filter
Sent (audit)

Address aliases used

Sending serviceFromAudit BCC
Merchant management templates (merchant-api)support@finmatch.iosupport+audit@finmatch.io
Monitoring alerts (/admin/send-monitoring-alert)support@finmatch.iosupport+audit@finmatch.io
Per-merchant config drift regression (template send)support@finmatch.iosupport+audit@finmatch.io
Finance assistant customer enquiry receiptfinance.assistant@finmatch.iofinance.assistant+audit@finmatch.io

The audit BCC for monitoring alerts is hardcoded in cloud-run/merchant-api/index.js (MONITORING_ALERT_BCC) so it cannot drift if Cloud Run env vars change. The other audit BCCs are driven by the SENDGRID_BCC env var on each Cloud Run service (set in the deploy workflows).

Gmail filter setup

Run these once per mailbox. You must be signed in as the mailbox owner (or have delegated access with filter permissions).

support@finmatch.io

  1. Open Gmail as support@finmatch.io.

  2. Settings (gear) -> See all settings -> Filters and Blocked Addresses -> Create a new filter.

  3. In the To field enter:

    support+audit@finmatch.io
  4. Click Create filter.

  5. Tick:

    • Skip the Inbox (Archive it)
    • Mark as read
    • Apply the label: create a new label called Sent (audit)
    • (Optional) Never send it to Spam
  6. Click Create filter.

finance.assistant@finmatch.io

Repeat the steps above, signed in as finance.assistant@finmatch.io, with the To field set to:

finance.assistant+audit@finmatch.io

Use the same label name Sent (audit) so the audit experience is consistent across both inboxes.

Verifying the filter

  1. Trigger a known send. Easiest options:
    • Admin -> Emails -> Merchant management -> open a merchant and send the Header snippet template.
    • Manually run .github/workflows/merchant-config-monitoring.yml via workflow_dispatch in GitHub Actions.
  2. In the relevant Gmail inbox, click the Sent (audit) label in the left sidebar.
  3. Confirm the new mail appears, and that it is not in Inbox.

If the mail lands in Inbox instead of (or as well as) the label, the filter's Skip the Inbox tick was missed — edit the filter and add it.

Limitations

  • Open / bounce status is not visible from the audit label. Gmail only knows about the BCC self-copy, not the recipient's delivery outcome. For deliverability investigations use the SendGrid dashboard directly.
  • The audit copy is not a perfect facsimile. Gmail rewrites some headers on inbound; treat it as proof of send + body content, not as a forensic source.
  • Plus-addressing on the From mailbox could be filtered out by a recipient's mail server in the unlikely event the BCC alias is ever exposed externally. It is not, currently — the BCC is only used for internal self-routing.
  • Admin UI: /emails — accordion of every email-sending path with its From / To / Reply-To / BCC.
  • Merchant API: cloud-run/merchant-api/index.js
    • Pinned monitoring constants near the top of the file.
  • Finance Assistant: cloud-run/finance-assistant/index.js
    • sendEnquiryEmail() and buildEnquiryEmail().