gigafibre-fsm/scripts/campaigns/templates/gift-email-fr.html
louispaulb 37896421c3 feat(campaigns): MVP gift campaign sender (Node CLI + FR email template)
User context: needs to send Giftbit gift cards to 203 customers with a
branded French email instead of Giftbit's English-only default delivery.
Giftbit's own UI/API can issue the gifts but its email is English; this
MVP bridges the gap by taking the gift URLs back from Giftbit, pairing
them with our contact CSV, and sending personalized FR emails through
the Mailjet SMTP that's already wired up for ERPNext invoice mail.

Three files in scripts/campaigns/:

1. send_gift_campaign.js — Node CLI. Two CSV inputs (gifts + contacts),
   matches by row order (default) or email key, renders the HTML
   template with mustache-style {{firstname}} / {{gift_url}} / etc.,
   sends via nodemailer with configurable SMTP + throttle.
   --dry-run writes per-recipient previews to disk for visual review
   before flipping to live mode. Results CSV with per-row status
   (sent / failed / dry-run) + error message + timestamp is written
   next to the script for follow-up on failures.

2. templates/gift-email-fr.html — branded French email. Table-based
   layout (the only thing that renders consistently in Gmail / Outlook /
   iOS Mail / Apple Mail / Bell Sympatico). Indigo gradient header,
   centered CTA button, contextual {{description}} line citing the
   service address, support contact in the footer, no inline images
   (defers to text + colour blocks to dodge image-blocking).

3. contacts_from_legacy.py — replaces the ad-hoc /tmp Python I ran
   earlier with a proper repo'd version. Same multi-email handling
   options (first / split / skip) as I offered the user; defaults to
   "first" = 1 gift per household, which is what they chose. Title-
   cases the address with French article rules (de / du / la / aux
   stay lowercase, 1re / 2e ordinals stay lowercase too).

4. README.md — end-to-end usage with the actual SMTP env vars from
   /opt/targo-hub/.env and the matching strategy decision matrix.

Validated end-to-end with a 5-row dry run: matching works, accents
preserved (Amélie, Geneviève, Marc-André), {{firstname}} interpolates,
gift URLs land in the rendered button href, address shows in the
contextual footer line. Previews written to disk for visual QA.

NOT in this MVP (out of scope, can come next if we end up running
gift campaigns regularly):
  - No persistence to ERPNext doctype (no Gift Campaign / Recipient
    records — pure CLI, results CSV is the audit trail)
  - No click-tracking redirect (the gift_url goes verbatim to the
    recipient; Giftbit's own API/dashboard reports redemption status,
    which is the more relevant signal than "clicked the link")
  - No ops UI page (CLI is fine for one-shot; if this becomes regular
    we wrap it in services/targo-hub/lib/gift-campaign.js + a Vue page)
2026-05-21 15:51:01 -04:00

100 lines
4.1 KiB
HTML

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Un cadeau de Gigafibre</title>
</head>
<body style="margin:0; padding:0; background:#f5f6fa; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; color:#1f2937; line-height:1.5;">
<!-- Spacer above the card -->
<div style="height:32px;"></div>
<table role="presentation" width="100%" cellspacing="0" cellpadding="0" border="0">
<tr>
<td align="center">
<table role="presentation" width="600" cellspacing="0" cellpadding="0" border="0"
style="max-width:600px; background:#ffffff; border-radius:14px; overflow:hidden; box-shadow:0 6px 24px rgba(15,23,42,0.07);">
<!-- Header band -->
<tr>
<td style="background:linear-gradient(135deg,#4f46e5 0%, #7c3aed 100%); padding:36px 32px 28px; text-align:center; color:#ffffff;">
<div style="font-size:0.78rem; font-weight:700; letter-spacing:0.12em; text-transform:uppercase; opacity:0.85;">
Gigafibre &middot; Récompense
</div>
<div style="font-size:2.2rem; line-height:1.1; margin-top:10px; font-weight:800;">
🎁 Un cadeau pour vous
</div>
</td>
</tr>
<!-- Body -->
<tr>
<td style="padding:36px 36px 12px;">
<p style="margin:0 0 16px; font-size:1.05rem;">Bonjour {{firstname}},</p>
<p style="margin:0 0 16px;">
Merci de faire partie de la famille Gigafibre. Pour vous remercier
de votre fidélité, voici une carte-cadeau d'une valeur de
<strong>{{amount}}</strong>, utilisable sur les marchands de votre choix.
</p>
<!-- CTA button -->
<div style="text-align:center; margin:32px 0 28px;">
<a href="{{gift_url}}"
style="display:inline-block; padding:16px 36px; background:#4f46e5; color:#ffffff;
text-decoration:none; font-weight:700; font-size:1.05rem;
border-radius:10px; box-shadow:0 4px 12px rgba(79,70,229,0.35);">
Récupérer mon cadeau →
</a>
</div>
<p style="margin:0 0 6px; font-size:0.9rem; color:#6b7280;">
Le lien vous mène à une page sécurisée où vous pourrez choisir la
marque qui vous fait plaisir (Amazon, Tim Hortons, SAQ, App Store,
et plusieurs autres).
</p>
{{#expiry}}
<p style="margin:6px 0 0; font-size:0.85rem; color:#9ca3af;">
⏰ Le lien expire le <strong>{{expiry}}</strong>.
</p>
{{/expiry}}
</td>
</tr>
<!-- Why this email -->
<tr>
<td style="padding:0 36px 28px;">
<div style="border-top:1px solid #e5e7eb; padding-top:20px; font-size:0.82rem; color:#6b7280;">
Vous recevez ce cadeau parce que vous êtes client(e) Gigafibre à
l'adresse <strong style="color:#374151;">{{description}}</strong>.
Si vous avez la moindre question, écrivez-nous à
<a href="mailto:facturation@targointernet.com" style="color:#4f46e5;">facturation@targointernet.com</a>
ou appelez-nous au <a href="tel:5142421500" style="color:#4f46e5;">514 242-1500</a>.
</div>
</td>
</tr>
<!-- Footer band -->
<tr>
<td style="background:#f9fafb; padding:18px 32px; text-align:center; border-top:1px solid #e5e7eb;">
<div style="font-size:0.75rem; color:#9ca3af;">
Gigafibre — Internet fibre optique au Québec<br>
<a href="https://www.gigafibre.ca" style="color:#9ca3af; text-decoration:underline;">www.gigafibre.ca</a>
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!-- Spacer below the card -->
<div style="height:48px;"></div>
</body>
</html>