Our per-recipient status relies on (a) the SMTP 250 at send time and (b)
webhooks Mailjet pushes afterward — a missed/delayed webhook could leave a
recipient stuck on a stale status. This queries Mailjet's own Message API
(GET /v3/REST/message?CustomID=...) directly, using the CustomID we already
stamp on every send, and compares Mailjet's authoritative Status against
what we have locally.
- campaigns.js: mailjetLookupByCustomId() (reuses the SMTP API key/secret
for REST auth) + reconcileCampaignWithMailjet(id, {limit}), which
prioritizes failed/bounced recipients first, then samples the rest.
compareStatus() distinguishes a real problem from normal webhook lag:
Mailjet being "ahead" of us (e.g. already 'opened' while we still show
'sent') is fine; Mailjet having NO record of a message we think we sent,
or reporting success where we recorded 'failed', are flagged.
- New route: GET /campaigns/:id/mailjet-reconcile?limit=N.
- CampaignDetailPage.vue: "Vérifier avec Mailjet" button + results dialog.
Verified against the real production campaign right after deploy: sampled
20 live recipients, 0 discrepancies, confirming both the feature and our
existing bookkeeping are accurate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>