SOP Alignment: SOP-006 (Shipping & Logistics) Constitution Compliance: Articles I (Backbone as source of truth), II (Stateless execution), III (Auditability), IV (SOP alignment) Last Updated: 2026-03-01 Status: Active
This document describes all automated processes for managing Outlook emails, attachments, calendar events, and project archiving within the MDL Ops Engine.
The Outlook automation suite consists of Python scripts and n8n workflows that reduce manual overhead in project organization, document management, and financial ingestion. All scripts are idempotent (safe to re-run) and use state files to prevent duplicate processing.
organize_outlook_emails.py)01_Sales_Lifecycle.ML2026xxxx) in the subject or body and moves the message to the corresponding folder. Creates new folders if they don't exist.sync_outlook_attachments.py)data/processed_ids.json to track already downloaded files.archive_old_projects.py)02_Archive directory.outlook_tagger.py)tag_message_with_category() โ applies Outlook category colours to emails (e.g. ๐ด "QBO Bill Created").create_bill_calendar_event() โ creates a ๐ฆ Bill Logged calendar event on the invoice date.create_bill_due_reminder() โ creates a โ ๏ธ Bill Due calendar reminder on the calculated payment due date._graph_headers() โ returns valid Microsoft Graph API auth headers.These scripts can be run manually from the terminal or scheduled via Task Scheduler:
# Sync attachments
python scripts/sync_outlook_attachments.py
# Organize emails by project
python scripts/organize_outlook_emails.py
# Archive old projects
python scripts/archive_old_projects.py
All n8n workflows follow the naming convention: [Human Description] (SOP-006-[SUBTAG])
See the full lifecycle map: SOP006_n8n_Automation_Map.md
(SOP-006-TRACKING) โ
LIVE| Field | Value |
|---|---|
| Trigger | Outlook Trigger โ polls every 30 min for carrier shipment status emails |
| Actions | Sends to /webhook/ingest-tracking โ logs to Supabase, sends delivery notifications |
| SOP Reference | SOP-006 ยง5.6, ยง6.1 |
| n8n Workflow Name | Package Tracking Ingest (SOP-006-TRACKING) |
(SOP-006-INVOICING) โ
LIVE| Field | Value |
|---|---|
| Trigger | Outlook Trigger โ polls every 30 min for carrier invoice emails (TotalShip, UPS, FedEx, DHL, Purolator) + hourly folder sweep |
| Actions | PDF extraction โ Gemini AI parsing โ QBO Vendor lookup โ QBO Bill creation โ Supabase log โ 2 calendar events โ email notification โ email tagged |
| SOP Reference | SOP-006 ยง5.4.2 |
| n8n Workflow Name | Shipping Invoice Ingest (SOP-006-INVOICING) |
| n8n File | n8n-docker/SOP006_Shipping_Invoice_Monitor.json |
| Backend Script | scripts/ingest_shipping_invoice.py |
| API Endpoints | POST /webhook/ingest-invoice, POST /webhook/scan-invoice-folders |
/webhook/ingest-invoice) runs the background pipeline:shipping_invoices Supabase table.MDL_NOTIFY_EMAIL./webhook/scan-invoice-folders) catches any invoices that moved before the real-time trigger.# Dry run โ scan inbox but make NO writes (safe to test anytime)
docker exec intelligent-processor python /app/scripts/ingest_shipping_invoice.py --dry-run
# Live run โ Inbox + Logistics folders (last 30 days)
docker exec intelligent-processor python /app/scripts/ingest_shipping_invoice.py
# Custom folder + lookback window
docker exec intelligent-processor python /app/scripts/ingest_shipping_invoice.py \
--folders Inbox "03_Operations/Logistics/TotalShip" --days 7
shipping_invoices Tableโ Migration already applied as of 2026-03-01.
CREATE TABLE IF NOT EXISTS public.shipping_invoices (
id BIGSERIAL PRIMARY KEY,
invoice_number TEXT UNIQUE,
vendor_name TEXT,
invoice_date DATE,
po_reference TEXT,
currency TEXT DEFAULT 'CAD',
subtotal NUMERIC(12, 2),
tax NUMERIC(12, 2),
shipping_charge NUMERIC(12, 2),
total NUMERIC(12, 2),
qbo_bill_id TEXT,
source TEXT DEFAULT 'outlook_auto',
processed_at TIMESTAMPTZ DEFAULT NOW()
);
| Variable | Value | Description |
|---|---|---|
GEMINI_API_KEY |
AIzaSy... |
AI invoice data extraction (already set โ ) |
MDL_NOTIFY_EMAIL |
bernard.cresencia@mdlcommunications.com |
Invoice notification recipient (already set โ ) |
CLIENT_ID |
โ | Microsoft Graph API auth (already set โ ) |
CLIENT_SECRET |
โ | Microsoft Graph API auth (already set โ ) |
TENANT_ID |
โ | Microsoft Graph API auth (already set โ ) |
SUPABASE_URL |
โ | Supabase logging (already set โ ) |
SUPABASE_KEY |
โ | Supabase logging (already set โ ) |
data/ to track processed message IDs.data/tracking_ingest_state.json โ tracking workflowdata/invoice_ingest_state.json โ invoicing workflowshipping_invoices in Supabase with processed_at timestamp and source field.QBO Bill Created category for visual audit trail.confidence_score to Supabase if AI extraction returns it.SOP006_n8n_Automation_Map.md) is the authoritative reference for all sub-step statuses.secrets/o365_token.txt via FileSystemTokenBackend.TokenManager or trigger re-auth via the BSC admin panel.| Symptom | Likely Cause | Fix |
|---|---|---|
O365 not authenticated |
Token expired | Refresh OAuth token via TokenManager |
Gemini extraction failed (400) |
Prompt too long or malformed | Check invoice PDF โ use --dry-run to inspect |
QBO Vendor not found |
Vendor name in invoice doesn't match QBO DisplayName | Add/alias vendor in QBO; update _guess_vendor_from_sender() |
Supabase upsert failed |
Duplicate invoice_number with conflicting data |
Review shipping_invoices table; delete stale row if needed |
| Container restarting | Python path issue | Ensure ENV PYTHONPATH=/app in Dockerfile.processor |
| n8n workflow not triggering | Outlook credential expired in n8n | Re-authenticate the Microsoft Outlook credential in n8n settings |