# E-mails transactionnels — inventaire et conditions de déclenchement

Établi le 2026-08-29, en vue de l'ouverture publique du 1er septembre.
Recense **tous** les messages que le site peut expédier, qui les reçoit, et à
quelle condition exacte ils partent. Aucun autre envoi n'existe : le site ne
possède ni newsletter, ni relance panier, ni message publicitaire.

---

## 1. Comment un e-mail sort du site

| Élément | Valeur |
|---|---|
| Expéditeur | `Vulcan'Affûtage <no-reply@vulcanaffutage.com>` |
| Transport | SMTP OVH (`ssl0.ovh.net:587`, STARTTLS), variable `MAILER_DSN` |
| Répondre à | valeur du réglage `contact.email` (défaut `vulcanaffutage@gmail.com`) — sauf l'alerte « nouvelle demande d'affûtage », où le `Reply-To` est l'établissement demandeur, pour répondre d'un clic |
| Logo | image jointe en CID, jamais une URL distante (les messageries bloquent les images externes) |
| Mise en page | `templates/emails/v2/_layout.html.twig` pour la boutique et l'affûtage ; gabarits historiques dédiés pour les 5 e-mails de compte |

**Deux garde-fous d'environnement**, à connaître avant toute campagne de test :

- **`MAILER_CATCH_ALL`** — si la variable contient une adresse, l'enveloppe SMTP
  de *tout* message sortant est réécrite vers elle. L'en-tête `To:` conserve le
  destinataire d'origine, ce qui permet de vérifier à qui le message *serait*
  parti. Tant que cette variable est remplie, **aucun client ne reçoit rien.**
  Elle doit être vide en production.
- **`MAILER_DSN=null://null`** — sur le poste de développement : les messages
  sont construits mais jamais remis.

Aucun envoi n'est bloquant : un e-mail qui échoue est journalisé, l'opération
métier (encaissement, changement de statut, activation) reste acquise.

---

## 2. Accès au compte — 5 e-mails

Ces messages partent directement depuis les contrôleurs d'authentification.

| # | Objet | Destinataire | Déclencheur exact |
|---|---|---|---|
| 1 | `Inscription Vulcan'Affûtage` | le nouvel inscrit | Formulaire `/inscription` validé : anti-robot franchi (leurre vide, ≥ 3 s de remplissage, pas d'inscription depuis cette session dans les 15 min), jeton CSRF valide, e-mail non déjà utilisé, mot de passe conforme. Contient le **lien d'activation, valable 72 h**. |
| 2 | `Activation de votre compte` | l'inscrit | Nouvelle inscription avec une adresse déjà présente **mais jamais activée**, et plus de 2 min depuis le dernier envoi. Régénère le jeton. |
| 3 | `Activation de votre compte` | l'inscrit | `/send-new-activation-mail/{email}` (bouton « renvoyer »), compte non activé, plus de 2 min depuis le dernier envoi. |
| 4 | `Activation de votre compte` | le client | Clic sur un lien d'activation valide. Confirme l'activation et propose la connexion. |
| 5 | `Modification de votre mot de passe` | le client | `/demande-modification-mdp` avec une adresse **connue**. Plafonné à 5 demandes par heure et par adresse IP, et à une toutes les 2 min par session. Lien **valable 20 min**, à usage unique. Une adresse inconnue affiche la même page de succès mais **n'envoie rien** — l'existence d'un compte ne doit pas être devinable. |

> **Corrigé le 2026-08-29** — les liens d'activation et de réinitialisation
> étaient générés en chemin relatif (`/confirm-email/…`). Dans une messagerie,
> un lien sans nom de domaine ne mène nulle part : **aucun compte n'était
> activable**. Ils sont désormais absolus et testés
> (`tests/Client/ParcoursAuthTest.php`).

> **Point de vigilance** — trois messages différents partagent l'objet
> « Activation de votre compte » (#2, #3 et #4). Ce n'est pas un défaut de
> fonctionnement, mais un client qui reçoit deux fois le même objet peut ouvrir
> le mauvais. À différencier si le sujet remonte.

---

## 3. Commande — 7 e-mails

| # | Objet | Destinataire | Déclencheur exact |
|---|---|---|---|
| 6 | `Merci ! Votre commande XXX est confirmée` | le client | Retour PayPal capturé avec succès : statut `COMPLETED`, montant encaissé égal au total de la commande, devise EUR, aucune pièce vendue entre-temps. C'est **le seul e-mail qui prouve l'achat au client**. |
| 7 | `Nouvelle commande XXX — NN,NN €` | la boutique (`contact.email`) | Même instant que le #6. |
| 8 | `On vous offre une carte cadeau` / `Votre carte cadeau est prête` / `Vos cartes cadeaux sont prêtes` | le bénéficiaire, ou l'acheteur | Même instant, **si la commande contient des cartes cadeaux**. Une carte dotée d'une adresse de bénéficiaire part directement chez lui ; toutes les autres sont regroupées dans un seul message à l'acheteur. |
| 9 | `Votre colis est en route !` | le client | Un gestionnaire enregistre un numéro de suivi depuis `/gestion/commandes/…` **avec la case « prévenir le client » cochée**. Jamais automatique. |
| 10 | `Mise à jour de votre commande XXX` | le client | Un gestionnaire change le statut d'une commande **avec la case cochée**. |
| 11 | `Votre colis est arrivé !` | le client | **Automatique (cron)** : la synchronisation du suivi La Poste détecte la livraison. Une seule fois par commande. |
| 12 | `Votre commande vous a plu ?` | le client | **Automatique (cron)**, 2 jours après la livraison — ou après la création pour une commande 100 % numérique payée. Une seule fois par commande, uniquement dans les 30 jours suivants, et seulement si le réglage `notify.satisfaction_email` n'est pas à `0`. |

Les e-mails 9 et 10 ne partent **jamais** sans action humaine explicite : la case
« prévenir le client » est décochée par défaut. Aucun des sept ne part si le
compte client n'a pas d'adresse.

---

## 4. Atelier — 3 e-mails

| # | Objet | Destinataire | Déclencheur exact |
|---|---|---|---|
| 13 | `C'est demain ! Votre atelier chez Vulcan'Affûtage` | le participant | **Automatique (cron)** : réservation confirmée et payée dont le créneau démarre dans les 24 h. Une seule fois. |
| 14 | `Votre réservation d'atelier est annulée` | le participant | Un gestionnaire annule la réservation, ou supprime l'atelier entier. Le motif saisi est repris dans le message. |
| 15 | `Votre réservation d'atelier a expiré` | le participant | **Automatique (cron)** : réservation prise en ligne, jamais payée, plus de 45 min après sa création. La place est rendue. **Exception** : une place réservée via une carte cadeau ne déclenche aucun envoi — le bénéficiaire ignore encore qu'on lui offre l'atelier. |

---

## 5. Carte cadeau vendue au comptoir — 1 e-mail

| # | Objet | Destinataire | Déclencheur exact |
|---|---|---|---|
| 16 | `On vous offre une carte cadeau` | le bénéficiaire | Création d'un bon depuis `/gestion/bons-cadeaux/nouveau` **avec une adresse de bénéficiaire renseignée**. Sans adresse, aucun envoi : le code est remis en main propre, et l'écran le rappelle. |

---

## 6. Affûtage professionnel — 7 e-mails

| # | Objet | Destinataire | Déclencheur exact |
|---|---|---|---|
| 17 | `Votre demande d'affûtage a bien été envoyée` | l'établissement | Formulaire `/affutage` déposé : leurre vide, ≥ 4 s de remplissage, CSRF valide, moins de 5 demandes en 24 h depuis cette IP. |
| 18 | `Nouvelle demande d'affûtage pro — <établissement>` | la boutique | Même instant. `Reply-To` = l'établissement. |
| 19 | `Demande XXX validée — envoyez-nous vos lames` | l'établissement | Le gestionnaire valide la demande. **Envoi coché par défaut**, décochable. Contient l'adresse de l'atelier. |
| 20 | `Votre demande d'affûtage XXX` | l'établissement | Le gestionnaire refuse la demande. Motif repris s'il est saisi. Envoi coché par défaut. |
| 21 | `Nous avons bien reçu vos couteaux` | l'établissement | Le gestionnaire marque le colis comme réceptionné. Envoi coché par défaut. |
| 22 | `Suivi de votre envoi XXX` | l'établissement | Le gestionnaire saisit le suivi du colis **aller**. Sans ce message, l'établissement n'a aucun moyen de connaître ce numéro : l'étiquette est fournie par l'atelier. |
| 23 | `Vos lames sont en route vers votre établissement` | l'établissement | Le gestionnaire saisit le suivi du colis **retour**. |

Contrairement aux e-mails de commande, ceux de l'affûtage sont **cochés par
défaut** : le flux pro est une conversation suivie, où chaque étape attend une
réaction du client professionnel.

---

## 7. Ce qui dépend du cron

Quatre e-mails (#11, #12, #13, #15) ne partent **que** si la commande
`php bin/console app:cron` s'exécute. Sans elle :

- un colis livré n'est jamais annoncé au client, et la commande reste
  « expédiée » à l'écran ;
- aucun message de satisfaction ne part ;
- aucun rappel d'atelier la veille ;
- les places d'atelier non payées **restent bloquées indéfiniment**, ce qui
  ferme des créneaux à de vrais acheteurs.

La commande est idempotente et verrouillée : deux exécutions simultanées ne
font pas double emploi. Cadence conseillée : **toutes les 15 minutes**, à
planifier depuis le panneau OVH (les tâches planifiées du mutualisé ne passent
pas par le crontab utilisateur).

---

## 8. Vérifier sans écrire à personne

```bash
# Poste de développement : aucun message ne quitte la machine.
MAILER_DSN=null://null

# Recette : vrais envois SMTP, mais tous détournés vers une boîte de test.
MAILER_CATCH_ALL=adresse@exemple.fr
```

La suite de tests couvre les déclencheurs et le contenu :
`tests/Client/ParcoursAuthTest.php` (comptes), `tests/Gestion/Mail/`,
`tests/Gestion/Tracking/ReviewRequestServiceTest.php`,
`tests/Gestion/ReservationLifecycleTest.php`, `tests/Gestion/BonCadeauTest.php`,
`tests/Gestion/AffutageProPublicTest.php`,
`tests/EventListener/MailCatchAllListenerTest.php`.
