DocsAutoResponderProcess

Implemented notifications catalog#

Long-form reference for every outbound notification the AutoResponder pipeline sends today: exact To / Cc, subject templates, attachments, and body text as implemented in code.

For the compact recipient matrix, see NOTIFICATIONS_REFERENCE.html. Product decisions from the 2026-05-17 alignment are in meetingNotes.md. Deferred work: Deferred (N11) and IMPLEMENTATION_PLAN.html. Legacy 1.x / 2.x / 3.x IDs are mapped in Legacy ID mapping.

Derived from:


Notification index (N01–N12)#

Rows are sorted in pipeline send order. Every live email also receives the global Max + Vish Cc (see Global delivery rules) unless SMTP_NOTIFICATION_RECIPIENTS override is active. Index Cc shows role-specific Cc only; add Max + Vish for production routing unless override is on.

IDPhaseNameMethodToCcAttachmentsSubject
N01BatchHodor Prospect Importnotify_hodor_prospect_importVenuMax, Vishhodor_prospect_import_verification.csvHodor Prospect Import ready…
N02BatchMultipub follow-upnotify_multipub_subscriber_followup_batchAngel+YogeshMatt, Max, Vishmultipub_subscriber_followup.csvSubscriber follow-up needed…
N03BatchTarun undetermined sendernotify_tarun_undetermined_sender_reviewTarunMax, Vishtarun_undetermined_senders.csvUndetermined sender review…
N04Run endMarketing suppressionnotify_marketing_suppressionMarketing teamMax, Vish{BusinessUnit}_NoLongerThere_{YYYY-MM-DD}.csv (e.g. Marketing_NoLongerThere_2026-05-27.csv)Marketing suppression list…
N05Run endSai replacementsnotify_sai_action_itemsSaiMax, Vishoutput_document_alternate_contacts.csvNew replacements…
N06Run endSai manual reviewnotify_sai_action_itemsSaiMax, VishUp to 4 CSVsManual review action items…
N07Run endVenu CUPOLA auditnotify_venu_cupola_audit_filesVenuSai, Max, VishAudit + HR CSVCUPOLA audit log ready…
N08Run endIP4 run auditnotify_run_audit_for_ip4SaiMax, VishLog, CSVs, HTMLRun reports (no ACTION REQUIRED)
N09UploadTarun upload Yesnotify_multipub_subscriber_followup_from_uploadAngel+YogeshMatt, Tarun, Max, VishAllowlisted uploaded file (+ multipub_subscriber_followup.csv when items passed)Tarun confirmed…
N10UploadTarun upload Noappend_tarun_upload_audit_rowNo email
N11DeferredLeadership summarynotify_run_summary_for_leadershipLog only
N12CLI (post-run)Action items completion confirmationsend_action_items_completion_confirmationSame as N01–N07 owner per groupSame as original notificationNoneConfirm completion — {original N## title}…

Pipeline order: N01 → N02 → N03 (batch flush; each sends only when its in-memory queue has rows) → N04 → N05 or N06 when action-item CSVs exist → N07 → N08 → N11 scaffold (log only). N09/N10 are independent of the batch run.


Global delivery rules#

Email body assembly (every live send)#

Notifier._send_notification_email builds the SMTP body in this order (implemented in notifier.py + alignment_helpers.py). Every send includes an HTML alternative that bolds the subject and opening instructions. When SMTP_NOTIFICATION_RAW_MODE is false, metadata blocks are appended at the bottom of both plain and HTML parts.

  1. Main content — per notify_* method (documented under each N## below).
  2. Catalog banner — appended via format_notification_catalog_header only when SMTP_NOTIFICATION_RECIPIENTS is set, so dev/override recipients can map the message to a catalog entry. Production recipients (Sai, Venu, etc.) do not see the banner.
  3. Attachments guide — when at least one attachment survives the allowlist, format_attachment_guide appends a filename + one-line purpose for each file.
  4. Delivery note — when SMTP_NOTIFICATION_RECIPIENTS is non-empty, _smtp_override_disclosure_lines appends who actually received the message vs who it was intended for in production.

1. Catalog banner (SMTP override only)#

Omitted in production when mail goes to the intended role addresses. When SMTP_NOTIFICATION_RECIPIENTS is set, the banner is the last metadata block before the delivery note (after main content and attachments guide).

text
This message is notification catalog {ID} — {title from NOTIFICATION_CATALOG_NAMES}.
{optional one-line usage hint — N08 only today}
(See docs/NOTIFICATIONS_CATALOG.html)

{main content begins here}
IDBanner title (NOTIFICATION_CATALOG_NAMES)
N01Hodor Prospect Import
N02Multipub subscriber follow-up
N03Tarun undetermined sender
N04Marketing suppression
N05New replacements for inactive contacts (Sai / IP4)
N06Manual review action items (Sai / IP4)
N07Venu CUPOLA audit
N08Run audit (IP4)
N09Tarun upload — Yes (subscriber follow-up)
N10(no email — log only)
N11Leadership run summary (deferred; not emailed)
N12Action items completion confirmation

2. Main content (per notification)#

Everything after the banner until the attachments guide. Documented in full under each N01–N09 entry below, including per-notification Intended To / Intended Cc values used in the delivery note when SMTP_NOTIFICATION_RECIPIENTS is set.

3. Attachments guide (when files attach)#

text
Attachments:
  - {filename}: {one-line purpose from NOTIFICATION_ATTACHMENT_DESCRIPTIONS}

Unknown filenames fall back to: Supporting file from this run (see filename). output_document_*.csv files use: Output-document deliverable for this run.

4. Delivery note (when SMTP_NOTIFICATION_RECIPIENTS is set)#

Appended after the main content and attachments guide. Lists the override mailbox(es) that actually received the message and the intended production routing for that notification (To/Cc as computed before override). Each N## entry below documents its intended To/Cc for this footer.

text
--- Delivery note ---
SMTP_NOTIFICATION_RECIPIENTS is active; this message was delivered to the override list.
  Override To : {comma-separated addresses from SMTP_NOTIFICATION_RECIPIENTS}
  Intended To : {production To for this notification, or "(none)"}
  Intended Cc : {production Cc after _merge_cc — per-notification Cc + global Max + Vish, deduped vs To; or "(none)"}
  SMTP_ALWAYS_CC : {comma-separated from SMTP_ALWAYS_CC} (not added to delivery while override is active)   ← only when SMTP_ALWAYS_CC is set

Important: when override is active, SMTP sends To-only to Override To. Intended Cc (including Max, Vish, Matt, Sai, Tarun, etc.) and SMTP_ALWAYS_CC are informational in the body only — neither is added at SMTP time while override is on.


Configuration#

Env varRoleUsed by
NOTIFICATION_EMAIL_ANGELClient ServicesN02 + N09
NOTIFICATION_EMAIL_YOGESHClient ServicesSame as Angel
NOTIFICATION_EMAIL_MATTClient Services CcMultipub follow-up + Tarun upload Yes
NOTIFICATION_EMAIL_MAXSupervisorGlobal Cc; Venu audit per-row Cc
NOTIFICATION_EMAIL_VISHSupervisorGlobal Cc
NOTIFICATION_EMAIL_TARUNMultipub reviewN03; Cc on N09
NOTIFICATION_EMAIL_SAIIP4 / manual CupolaN05/N06 + N08 (ip4_audit_recipients())
NOTIFICATION_EMAIL_VENUVenuN01 Hodor Prospect Import To; N07 CUPOLA audit To
NOTIFICATION_EMAIL_ERINMarketing team (N04)Shared marketing mailbox — marketing-team-cbi@columbiabooks.com (env name is legacy; not a personal Erin inbox)
TARUN_UPLOAD_DIRUpload persistencePOST /multipub/upload (default ./tarun_uploads)
SMTP_NOTIFICATION_RECIPIENTSOverride ToAll notifications
SMTP_ALWAYS_CCExtra CcAll notifications when override off
NOTIFICATION_EMAIL_LEADERSHIPLeadership summaryDeferred — notify_run_summary_for_leadership (log-only today)
MOCK_ALL_SERVICES_FOR_DEVDev / CI mock-allMock connectors; notifier dry-run
WRITE_OPERATIONS_ENABLEDSimulation (no writes)When false, database writes are intercepted; notifications are log-only unless SMTP_NOTIFICATION_RECIPIENTS is set, in which case they send To-only to the override list.
SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROMSMTP transportAll sends via EmailService
TARUN_UPLOAD_API_*Upload APIOptional FastAPI host for POST /multipub/upload (see .env.example)

Notification details (by phase)#

Each entry documents: Method, Trigger, To, Cc, Subject, Attachments, and the complete body as assembled by _send_notification_email (banner → main content → attachments guide → delivery note). See Email body assembly for shared blocks.

Batch notifications — N01–N03 (flush_batch_notifications)#

Flush order in code: N01N02N03. In the normal batch run, each method is called only when its corresponding queue has rows. The CSV-only fallback behavior documented for N02/N03 is used by the resend CLI and any direct method call with an existing attachment directory.

N01 — notify_hodor_prospect_import#

FieldValue
Catalog IDN01
TriggerQueued Prospect Import rows during ActionEngine.execute() when Hodor automatic updates are off. Flushed at end of run; skipped when queue empty.
ToNOTIFICATION_EMAIL_VENU (skips cleanly when unset)
CcGlobal Max + Vish only
Subject[ACTION REQUIRED] [AutoResponder] Hodor Prospect Import ready for manual ingestion - {n} row(s)
Attachmentshodor_prospect_import_verification.csv only

Body (fixed in notifier.py):

text
Attached: Hodor Prospect Import verification rows generated by AutoResponder.

hodor_prospect_import_verification.csv is the review and update artifact for this run. Each row includes InboxSource (original mailbox), Email, Action, RequestedStatus, Title, ProsNum, Reason, PreviousEmail, and all SAC contact fields (comma-delimited UTF-8).

Use this file to review and apply Hodor updates manually.

Verification metadata columns (prepended in hodor_prospect_import_verification.csv): InboxSource, Email, Action, RequestedStatus, Title, ProsNum, Reason, PreviousEmail — then all SAC columns (sal, fname, …, employee_value).

Complete body (as sent) — intended routing for delivery note:

text
This message is notification catalog N01 — Hodor Prospect Import.
(See docs/NOTIFICATIONS_CATALOG.html)

Attached: Hodor Prospect Import verification rows generated by AutoResponder.

hodor_prospect_import_verification.csv is the review and update artifact for this run (InboxSource, Action, RequestedStatus, SAC fields).

Attachments:
  - hodor_prospect_import_verification.csv: Hodor Prospect Import verification rows for manual review and updates.

--- Delivery note ---                                    ← only when SMTP_NOTIFICATION_RECIPIENTS is set
SMTP_NOTIFICATION_RECIPIENTS is active; this message was delivered to the override list.
  Override To : {SMTP_NOTIFICATION_RECIPIENTS}
  Intended To : {NOTIFICATION_EMAIL_VENU}
  Intended Cc : {NOTIFICATION_EMAIL_MAX}, {NOTIFICATION_EMAIL_VISH}   (or "(none)" if unset)

N02 — notify_multipub_subscriber_followup_batch#

FieldValue
Catalog IDN02
TriggerQueued during ActionEngine.execute() for determined-sender Multipub evidence (active sub, sub in last 12 months, or purchase in last 12 months), including inactive/left-org and matched undeliverable paths. Flushed once at end of run only when the queue has rows. CSV-only fallback sends only when the notifier method is called directly with an empty queue and multipub_subscriber_followup.csv already exists, as in the resend CLI.
ToNOTIFICATION_EMAIL_ANGEL + NOTIFICATION_EMAIL_YOGESH (falls back to Max if both unset)
CcMatt when set; plus global Max + Vish
Subject[ACTION REQUIRED] [AutoResponder] Subscriber follow-up needed - {count} contact(s)
Attachmentsmultipub_subscriber_followup.csv — columns: contact_name, contact_email, subsnum, org, determination, active_subscription_count, last_12mo_subscription_count, last_12mo_purchase_count, product_list, source_subject, source_message_id, match_method, review_reason

Body (from build_multipub_subscriber_followup_payload in alignment_helpers.py):

text
The auto-responder detected that the people below are no longer available, retired, or unreachable, but they likely still have active or recent Multipub subscriptions.

Please reach out to these customers (or related contacts) and make the necessary subscription and contact adjustments.

Total contacts: {N}

============================================================
{idx}. {contact_name} ({contact_email})
   Subscriber number: {subsnum}
   Org: {org}                    (when present)
   Determination: {determination} (when present)
   Active subscriptions ({total}):
     - onum {onum}, {product_name}, expires {end_issue_date}
     ... and {N} more            (when more than 5)
   Subscriptions ended in last 12 months ({total}): ...
   Single-issue purchases in last 12 months ({total}): ...
   Source subject   : {source_subject}
   Source message id: {source_message_id}

CSV-only fallback (empty in-memory queue but multipub_subscriber_followup.csv on disk): subject [ACTION REQUIRED] [AutoResponder] Subscriber follow-up needed (see attached CSV); main content:

text
Please review the attached CSV. The auto-responder detected contacts who are no longer available but likely still have active or recent Multipub subscriptions. Reach out to customers and make the necessary adjustments.

Complete body (as sent) — intended routing for delivery note:

text
This message is notification catalog N02 — Multipub subscriber follow-up.
(See docs/NOTIFICATIONS_CATALOG.html)

{main content — full per-contact blocks above, or CSV-only fallback paragraph}

Attachments:
  - multipub_subscriber_followup.csv: Client Services queue: inactive/unavailable contacts with Multipub activity.

--- Delivery note ---
SMTP_NOTIFICATION_RECIPIENTS is active; this message was delivered to the override list.
  Override To : {SMTP_NOTIFICATION_RECIPIENTS}
  Intended To : {Angel}, {Yogesh}   (or Max if Angel/Yogesh unset)
  Intended Cc : {Matt when set}, {Max}, {Vish}   (Matt omitted if already in To)

N03 — notify_tarun_undetermined_sender_review#

FieldValue
Catalog IDN03
TriggerQueued when sender_identity_determined is false (e.g. source email is Manual Review Required). Flushed at end of run only when the queue has rows. CSV-only fallback sends only when the notifier method is called directly with an empty queue and tarun_undetermined_senders.csv exists on disk, as in the resend CLI.
ToNOTIFICATION_EMAIL_TARUN (skips cleanly when unset)
CcGlobal Max + Vish only
Subject[ACTION REQUIRED] [AutoResponder] Undetermined sender review - {count} case(s)
Attachmentstarun_undetermined_senders.csv — columns: message_id, raw_from, parsed_candidates, subject, body_excerpt, determination, run_directory

Body (from build_tarun_undetermined_sender_payload):

text
The auto-responder could not determine the true sender email for the messages below.

Please review the email bodies, match any subscriber you can find in Multipub, and respond through the Multipub upload endpoint:
  Yes - you found a subscriber (this will notify Client Services).
  No  - reviewed; no further action needed (logged only).

Total cases: {N}

============================================================
{idx}. Subject       : {subject}
   Raw From      : {raw_from}
   Candidate(s)  : {candidates}
   Determination : {determination}
   Message ID    : {message_id}
   Run directory : {run_directory}
   Body excerpt  :
     {body_excerpt}

CSV-only fallback main content:

text
Please review the attached cases where the auto-responder could not determine the true sender email. Reply through the Multipub upload endpoint with outcome yes or no.

Complete body (as sent) — intended routing for delivery note:

text
This message is notification catalog N03 — Tarun undetermined sender.
(See docs/NOTIFICATIONS_CATALOG.html)

{main content}

Attachments:
  - tarun_undetermined_senders.csv: Cases where the true sender email could not be determined (Tarun review).

--- Delivery note ---
SMTP_NOTIFICATION_RECIPIENTS is active; this message was delivered to the override list.
  Override To : {SMTP_NOTIFICATION_RECIPIENTS}
  Intended To : {NOTIFICATION_EMAIL_TARUN}
  Intended Cc : {NOTIFICATION_EMAIL_MAX}, {NOTIFICATION_EMAIL_VISH}

Run-end notifications — N04–N08 (main.py)#

Call order: notify_marketing_suppressionnotify_sai_action_itemsnotify_venu_cupola_audit_filesnotify_run_audit_for_ip4notify_run_summary_for_leadership (log only).

N04 — notify_marketing_suppression#

FieldValue
Catalog IDN04
TriggerAfter output documents are written; skipped when no *_NoLongerThere_*.csv deliverable exists in the run directory or NOTIFICATION_EMAIL_ERIN is unset
ToNOTIFICATION_EMAIL_ERIN → shared marketing team mailbox (marketing-team-cbi@columbiabooks.com in .env / in-code default). Not Erin’s personal inbox — the env var name is historical.
CcGlobal Max + Vish only
Subject[ACTION REQUIRED] [AutoResponder] Marketing suppression list - {run_dir.name}
AttachmentsSFMC-ready suppression import CSV(s) matching *_NoLongerThere_*.csv only (written from inactive-people rows at end of run). output_document_inactive_people.csv stays on disk for internal ops and is not emailed.
text
Here is the list of people that the auto responder marked as inactive (deceased, retired, left their organization, or no longer there).

Attached are suppression import files ready for SFMC ({filenames}).

Please suppress them from your marketing communications.

Run directory: {report_dir}

Complete body (as sent) — intended routing for delivery note:

text
This message is notification catalog N04 — Marketing suppression.
(See docs/NOTIFICATIONS_CATALOG.html)

Here is the list of people that the auto responder marked as inactive (deceased, retired, left their organization, or no longer there).

Attached are suppression import files ready for SFMC (Marketing_NoLongerThere_2026-05-27.csv).

Please suppress them from your marketing communications.

Run directory: {report_dir}

Attachments:
  - Marketing_NoLongerThere_2026-05-27.csv: SFMC suppression import file (Email Address, Status, Date Added).

--- Delivery note ---
SMTP_NOTIFICATION_RECIPIENTS is active; this message was delivered to the override list.
  Override To : {SMTP_NOTIFICATION_RECIPIENTS}
  Intended To : marketing-team-cbi@columbiabooks.com (NOTIFICATION_EMAIL_ERIN)
  Intended Cc : {NOTIFICATION_EMAIL_MAX}, {NOTIFICATION_EMAIL_VISH}

N05 — notify_sai_action_items (replacements-only)#

FieldValue
Catalog IDN05
TriggerAfter output documents when output_document_alternate_contacts.csv has rows and inactive-no-cupola, inactive-new-org, and actionable HR counts are all zero (meeting notes §1.5). Skipped when Sai unset.
ToNOTIFICATION_EMAIL_SAI (skips cleanly when unset)
CcGlobal Max + Vish only
Subject[ACTION REQUIRED] [AutoResponder] New replacements for inactive contacts - {run_dir.name}
AttachmentsN05: output_document_alternate_contacts.csv only

Body opening (fixed):

text
Please complete the manual Cupola actions below for this run.
Search Cupola for each person; if a record is missing, create it and associate it to the correct organization.
Reply when manual actions for this run are complete.

Run directory: {report_dir}

Then up to four sections with per-record blocks:

Per-record block formats (in body when section has rows):

text
SECTION 1 - New replacements for inactive contacts
===============================================
Rows: {N}

  {idx}. Original: {Email Received From}
     Replacement Name : {Alternate Person Name}
     Replacement Email: {Alternate Person Email}
     ...

SECTION 2 - Inactive contacts with no Cupola match (research)
  {idx}. Contact Email     : ...
SECTION 3 - Inactive contacts at a new organization
  {idx}. Contact Email     : ...  New Org Name : ...
SECTION 4 - Other Human Review action items
  {idx}. Contact Email     : ...  Reason : ...  Notes : ...  Suggested Action : ...

Complete body (as sent) — N05 only (replacements-only); intended routing:

text
This message is notification catalog N05 — New replacements for inactive contacts (Sai / IP4).
(See docs/NOTIFICATIONS_CATALOG.html)

Please complete the manual Cupola actions below for this run.
...
{SECTION 1 blocks only when N05}

Attachments:
  - output_document_alternate_contacts.csv: Replacement contacts suggested for inactive subscribers.

--- Delivery note ---
  Intended To : {NOTIFICATION_EMAIL_SAI}
  Intended Cc : {NOTIFICATION_EMAIL_MAX}, {NOTIFICATION_EMAIL_VISH}

N06 — notify_sai_action_items (manual review bundle)#

FieldValue
Catalog IDN06
TriggerCombined bundle when no-cupola, new-org, and/or actionable HR rows exist (meeting §1.6). The method returns without sending when none of the relevant CSV attachments exist.
ToNOTIFICATION_EMAIL_SAI (skips cleanly when unset)
CcGlobal Max + Vish only
Subject[ACTION REQUIRED] [AutoResponder] Manual review action items - {run_dir.name}
AttachmentsEvery relevant section CSV that exists (normally non-empty in generated run folders): output_document_alternate_contacts.csv, output_document_inactive_no_cupola_match.csv, output_document_inactive_new_org.csv, and/or generated output_document_human_review_action_items.csv for actionable SECTION 4 rows.

Same method, SECTION 1–4 layouts, and per-record formats as N05. Catalog banner and subject differ.

Complete body (as sent) — N06 (combined bundle); intended routing:

text
This message is notification catalog N06 — Manual review action items (Sai / IP4).
(See docs/NOTIFICATIONS_CATALOG.html)

{same opening paragraph and Run directory as N05}
{one or more SECTION 1–4 blocks with per-record detail}

Attachments:
  - {each attached CSV with output-document description}

--- Delivery note ---
  Intended To : {NOTIFICATION_EMAIL_SAI}
  Intended Cc : {NOTIFICATION_EMAIL_MAX}, {NOTIFICATION_EMAIL_VISH}

N07 — notify_venu_cupola_audit_files#

FieldValue
Catalog IDN07
TriggerAfter cupola_audit_log.csv is written every run (including zero-entry runs when file exists). json_path is accepted but never attached.
ToNOTIFICATION_EMAIL_VENU
CcSai and Max when distinct from Venu; plus global Max + Vish
Subject[ACTION REQUIRED] [AutoResponder] CUPOLA audit log ready for review - {entry_count} row(s) - {run_dir.name}
Attachmentscupola_audit_log.csv; cupola_audit_log_rollback_plan.csv when present; output_document_human_review.csv when present (metadata — actionable HR rows also go to Sai N05/N06)

Main content (fixed opening + dynamic counts):

text
Please review the attached Cupola audit log for this run and reply by email when you have finished processing the records.

Run directory: {csv_path.parent}
Audit entries: {entry_count}
Human Review rows: {total}                    ← when output_document_human_review.csv exists

Human Review counts by reason:               ← when HR CSV has rows
  - {reason}: {count}
  ...

Human Review reason key:
  - unknown_determination          LLM returned UNKNOWN
  - no_contact_match             Actionable outcome, no contact in any system
  - bounce_pending_rule          Bounce awaiting the Max + Vish rule
  - replacement_parse_fallback   Replacement alt-contact failed to parse
  - active_new_contact_no_cupola Active person is missing from CUPOLA
  - reactivation_candidate_inactive_cupola CUPOLA row is inactive but email indicates active
  - email_or_title_update_on_inactive_cupola Email/title update requested on inactive CUPOLA row
  - out_of_office_tracked_separately Out-of-office response awaiting split-out process

Complete body (as sent) — intended routing for delivery note:

text
This message is notification catalog N07 — Venu CUPOLA audit.
(See docs/NOTIFICATIONS_CATALOG.html)

{main content above}

Attachments:
  - cupola_audit_log.csv: CUPOLA changes applied or recommended during this run.
  - cupola_audit_log_rollback_plan.csv: Rollback SQL for auto-applied CUPOLA status changes.   ← when present
  - output_document_human_review.csv: Human Review metadata for every HR row in the run.     ← when present

--- Delivery note ---
  Intended To : {NOTIFICATION_EMAIL_VENU}
  Intended Cc : {Sai when ≠ Venu}, {Max when ≠ Venu}, {Max}, {Vish}   (actual merge/dedupe in code)

N08 — notify_run_audit_for_ip4#

FieldValue
Catalog IDN08
TriggerAfter processing reports, output documents, Cupola audit, classifier output, and batch_report.html are written. Returns false when no attachable files exist.
Tosettings.ip4_audit_recipients()NOTIFICATION_EMAIL_SAI
CcGlobal Max + Vish only
Subject[AutoResponder] Run reports - {run_dir.name} (no [ACTION REQUIRED] prefix)
AttachmentsAny present files after allowlist: processing_report.log (or configured report filename), processing_report_master.csv, processing_report_ip4.csv, category_summary_report.csv, batch_report.html. impact_report.txt is written on disk but not attached (impact metrics are inline in the body and in the log).

Body sections (built in notifier.py):

Main content (all sections optional except opening; built in notify_run_audit_for_ip4):

text
This email contains the run ledger and summary files for verification.

Run identity:
  Run directory : {report_dir}
  Run started   : {YYYY-MM-DD HH:MM:SS UTC (from folder name)}   ← when parseable

Email pull window (UTC):                        ← when backlog snapshot OK
  Start : {ISO8601}
  End   : {ISO8601}

Impact summary (this run):
  Run ID               : {run_id}
  Emails processed     : {N}  (messages handled in this batch)
  Records deactivated  : {N}  (auto-applied CUPOLA inactive transitions)
  Records added        : {N}  (successful contact_addition with contact_id)

This-run progress:                              ← backlog snapshot or master CSV
  Processed this run           : {N}
  Repository backlog estimate  : {N}

Category breakdown (category_summary_report.csv):   ← when file exists
  - {category}: {count}

Processing status breakdown (master CSV):           ← when master exists
  - {status}: {count}

IP4 ledger:
  processing_report_ip4.csv rows : {N}

Repository backlog snapshot:                        ← when snapshot OK
  Total candidates in window   : {N}
  Estimated still unprocessed  : {N}
  Oldest unprocessed ReceivedDate (UTC): {ISO8601 or (none - backlog empty)}
  Days behind (UTC calendar vs now): {N}

Complete body (as sent) — intended routing for delivery note:

text
This message is notification catalog N08 — Run audit (IP4).
Review the attached run ledgers and summaries to verify this batch. Use processing_report_ip4.csv for IP4-actionable rows; no reply needed unless something looks wrong.
(See docs/NOTIFICATIONS_CATALOG.html)

{main content sections above}

Attachments:
  - processing_report.log: Full per-email processing trace, run summary, and impact headline metrics.
  - processing_report_master.csv: Ledger of every email in the run (full internal column set).
  - processing_report_ip4.csv: IP4-actionable emails only (filtered categories, 23-column order).
  - category_summary_report.csv: LLM category counts for the run.
  - batch_report.html: HTML dashboard summarizing run outcomes.
  (only files that exist on disk are listed)

--- Delivery note ---
  Intended To : {NOTIFICATION_EMAIL_SAI}
  Intended Cc : {NOTIFICATION_EMAIL_MAX}, {NOTIFICATION_EMAIL_VISH}

Upload API — N09–N10 endpoint#

POST /multipub/upload — multipart file plus form outcome=yes|no (default yes). Implemented in tarun_upload_api.py.

N09 — notify_multipub_subscriber_followup_from_upload#

FieldValue
Catalog IDN09
Triggeroutcome=yes after file is stored under TARUN_UPLOAD_DIR. The current upload endpoint passes no parsed items, so it normally uses the short “please review upload” body and original uploaded filename.
ToAngel + Yogesh (same as N02)
CcMatt; Tarun (receipt, when not already in To); global Max + Vish
SubjectWith parsed items: [ACTION REQUIRED] [AutoResponder] Tarun confirmed subscriber match - Subscriber follow-up needed - {n} contact(s). Without items: … Tarun confirmed subscriber match - please review upload
AttachmentsUploaded file under original filename only if it survives the notification allowlist (.csv, .txt, .log, .html); optional inline multipub_subscriber_followup.csv from the payload builder when items are passed. Uploaded .tsv, .xls, and .xlsx files are accepted and audited by the API but are dropped from the notification email by the shared attachment filter.

Main content — no parsed items (current Yes-path default):

text
Tarun reviewed an undetermined-sender case and confirmed a subscriber match in Multipub.

Please review the attached file and reach out to the customer or related contacts to make the necessary subscription and contact adjustments.

Note from Tarun:                                              ← when upload form includes a note
{note text}

This body text is fixed in code. If the uploaded file has a suffix accepted by the upload API but not by filter_notification_attachments (for example .xlsx), the email can still say “attached file” while the attachment is omitted.

Main content — with items: same per-contact blocks as N02 from build_multipub_subscriber_followup_payload (subject prefix adds Tarun confirmed subscriber match -).

Complete body (as sent) — intended routing for delivery note:

text
This message is notification catalog N09 — Tarun upload — Yes (subscriber follow-up).
(See docs/NOTIFICATIONS_CATALOG.html)

{main content — short message or N02-style blocks}

Attachments:
  - {uploaded_filename}: Supporting file from this run (see filename).   ← only if upload filename is allowlisted; or multipub CSV description

--- Delivery note ---
  Intended To : {Angel}, {Yogesh}
  Intended Cc : {Matt}, {Tarun when not in To}, {Max}, {Vish}

N10 — append_tarun_upload_audit_row — no email#

outcome=no appends to {TARUN_UPLOAD_DIR}/tarun_upload_audit.csv with columns: timestamp, original_filename, outcome, uploaded_by, note. No notification is sent.


Action items tracker (N01–N07)#

After each run, main.py calls append_action_items_for_run(report_dir) to append one row per action notification email (N01–N07 that had attachments) to action_items_tracker.csv (default under processing_reports/; override ACTION_ITEMS_TRACKER_PATH). Each row has ActionItemCount, a file breakdown in Summary, and Completed=false until an operator marks it done. See DATA_DICTIONARY §32. Catalog N12 is a separate CLI follow-up (not appended to the tracker) that asks each N01–N07 notification owner to reply confirming work for that run.


Action items completion confirmation (N12)#

CLI: auto-responder-request-action-item-confirmation <processing_reports/run_*> (send_action_items_confirmation.py).

Reads the same artifacts as collect_action_item_detail_rows, groups by NotificationId (N01–N07), and sends one N12 email per group to the notification owner (Venu for N01/N07, Sai for N05/N06, Angel+Yogesh for N02, etc.). Does not inspect the Sent mailbox.

FlagBehavior
--dry-runNotifier(dry_run=True) — log only, no SMTP
--test-email ADDRDeliver To-only to ADDR; footer shows Intended To / Intended Cc for production routing (CLI override disclosure)
--only N01,N06Limit to comma-separated notification IDs

Subject: [ACTION REQUIRED] [AutoResponder] Confirm completion — {original N## title} — {run date}

Body: Reply request for the run date, reference to the original N## notification, row counts, breakdown by source file, and up to 25 item lines from tracker fields.


Resend from an output folder#

CLI: auto-responder-send-output-emails <processing_reports/run_*> (send_output_folder_emails.py).

FlagBehavior
--dry-runNotifier(dry_run=True) — log only, no SMTP
--skip-queuedSkip batch notifications (N01–N03) emails (Hodor, Multipub follow-up, Tarun undetermined); send once-per-run bundle only

Dispatch groups (in order):

  1. N01 hodor-prospect-import — loads rows from hodor_prospect_import_verification.csv
  2. N02 multipub-subscriber-followup — CSV-only resend when multipub_subscriber_followup.csv exists
  3. N03 tarun-undetermined-senders — CSV-only when tarun_undetermined_senders.csv exists
  4. N04 marketing-suppression — when *_NoLongerThere_*.csv exists in the run folder
  5. N05/N06 sai-action-items
  6. N07 venu-cupola-audit — rebuilds entry count from JSON or CSV
  7. N08 ip4-run-audit — restores impact_report and backlog from processing_report.json when present

Leadership summary is not resent (not implemented).


Deferred (N11) / not implemented#

notify_run_summary_for_leadership#

Called from main.py after the IP4 run audit. Does not send email today. Builds a metrics-only preview body and logs at INFO:

text
AutoResponder run summary (metrics only)
Run directory: {report_dir}
Emails processed: …
Records deactivated: …
Records added: …
Email/title corrections (auto-applied): …   (from cupola_audit_log.json when present)
Distinct organizations in contact additions: …   (or "not tracked yet")

Per meeting notes and IMPLEMENTATION_PLAN.html, the live send should go to NOTIFICATION_EMAIL_LEADERSHIP with no CSV attachments, only after Sai confirms action items and Venu confirms the audit log (reply email or API). Intended subject: [AutoResponder] Run summary - {run_dir.name}.

Preview body (log-only today) — uses the catalog banner but does not send SMTP:

text
This message is notification catalog N11 — Leadership run summary (deferred; not emailed).
(See docs/NOTIFICATIONS_CATALOG.html)

AutoResponder run summary (metrics only)
Run directory: {report_dir}
Emails processed: {N}
Records deactivated: {N}
Records added: {N}
Email/title corrections (auto-applied): {N}   ← when cupola_audit_log.json present
Distinct organizations in contact additions: {N}   ← or "Organizations added: not tracked yet"

When implemented, intended delivery note would show Intended To : {NOTIFICATION_EMAIL_LEADERSHIP} and global Max + Vish in Intended Cc.


Legacy ID mapping#

Prior docs and meeting notes used tiered IDs (1.x, 2.x, 3.x). Use N01–N11 in new mail banners and references.

LegacyNewNotes
1.1N02Multipub batch follow-up
1.2N03Tarun undetermined sender
1.3N01Hodor Prospect Import (flush order changed)
2.1N08IP4 run audit
2.2N05 or N06Replacements-only vs manual-review bundle (meeting §1.5 → N05, §1.6 → N06)
2.3N07Venu CUPOLA audit
2.4N04Marketing suppression
3.1N09Tarun upload Yes
3.2N10Tarun upload No (log only)
N11Leadership summary (deferred)

Open follow-ups#