feat(api): bascule des envois mail sur Resend (fin de Mailpit en dev)
- MAIL_DRIVER=resend par défaut, from rubis@arthurbarre.fr (domaine vérifié) - replyTo posé sur user.email dans les relances : les réponses des clients reviennent au patron de la TPE, pas dans notre boîte transactionnelle - ajout d'une commande Ace `send:test-email` pour valider la conf (driver, from, SPF/DKIM/clé API) sans passer par tout le flow facture Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
b8dec6d494
commit
a790455ae1
@ -49,14 +49,15 @@ S3_SECRET_KEY=rubis-dev-secret
|
||||
S3_FORCE_PATH_STYLE=true
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Mail (Mailhog en dev, Resend en prod)
|
||||
# Mail (Resend par défaut, Mailpit en fallback dev via MAIL_DRIVER=smtp)
|
||||
#--------------------------------------------------------------------
|
||||
MAIL_FROM_ADDRESS=relances@rubis-sur-l-ongle.fr
|
||||
MAIL_FROM_ADDRESS=rubis@arthurbarre.fr
|
||||
MAIL_FROM_NAME=Rubis Sur l'Ongle
|
||||
MAIL_DRIVER=smtp
|
||||
MAIL_DRIVER=resend
|
||||
RESEND_API_KEY=
|
||||
# Fallback Mailpit (si MAIL_DRIVER=smtp)
|
||||
SMTP_HOST=localhost
|
||||
SMTP_PORT=1025
|
||||
RESEND_API_KEY=
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# OCR (Mistral)
|
||||
|
||||
@ -43,6 +43,12 @@ export async function sendRelanceEmail({ invoice, client, step, user }: RelanceP
|
||||
// Texte brut pour V1 — on ajoutera un template HTML quand on aura
|
||||
// décidé d'un look graphique pour les relances.
|
||||
.text(body)
|
||||
// Reply-To pointe sur l'utilisateur Rubis : si le client final répond
|
||||
// à la relance, sa réponse arrive chez le patron de la TPE, pas dans
|
||||
// notre boîte transactionnelle.
|
||||
if (user?.email) {
|
||||
m.replyTo(user.email, user.fullName ?? user.email)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
61
apps/api/commands/send_test_email.ts
Normal file
61
apps/api/commands/send_test_email.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { BaseCommand, args, flags } from '@adonisjs/core/ace'
|
||||
import type { CommandOptions } from '@adonisjs/core/types/ace'
|
||||
import mail from '@adonisjs/mail/services/main'
|
||||
import env from '#start/env'
|
||||
|
||||
/**
|
||||
* Envoie un email de test via le mailer courant (typiquement Resend)
|
||||
* pour valider la conf SPF/DKIM/clé API sans passer par toute la chaîne
|
||||
* facture → job BullMQ.
|
||||
*
|
||||
* node ace send:test-email arthur@example.com
|
||||
* node ace send:test-email arthur@example.com --reply-to=patron@tpe.fr
|
||||
*/
|
||||
export default class SendTestEmail extends BaseCommand {
|
||||
static commandName = 'send:test-email'
|
||||
static description = 'Envoie un email de test via le mailer configuré (Resend en prod)'
|
||||
|
||||
static options: CommandOptions = {
|
||||
startApp: true,
|
||||
}
|
||||
|
||||
@args.string({ description: 'Adresse destinataire' })
|
||||
declare to: string
|
||||
|
||||
@flags.string({ description: 'Adresse de reply-to (optionnelle)' })
|
||||
declare replyTo?: string
|
||||
|
||||
async run() {
|
||||
const driver = env.get('MAIL_DRIVER', 'smtp')
|
||||
const fromAddress = env.get('MAIL_FROM_ADDRESS', 'relances@rubis-sur-l-ongle.fr')
|
||||
const fromName = env.get('MAIL_FROM_NAME', "Rubis Sur l'Ongle")
|
||||
|
||||
this.logger.info(`Driver: ${driver}`)
|
||||
this.logger.info(`From: ${fromName} <${fromAddress}>`)
|
||||
this.logger.info(`To: ${this.to}`)
|
||||
if (this.replyTo) this.logger.info(`ReplyTo: ${this.replyTo}`)
|
||||
|
||||
const mailer = mail.use(driver)
|
||||
const response = await mailer.send((m) => {
|
||||
m.from(fromAddress, fromName)
|
||||
.to(this.to)
|
||||
.subject('[Rubis] Test d\'envoi via Resend')
|
||||
.text(
|
||||
`Bonjour,\n\n` +
|
||||
`Ceci est un email de test envoyé depuis Rubis Sur l'Ongle.\n` +
|
||||
`Si vous recevez ce message, la conf Resend (SPF/DKIM/API key) est OK.\n\n` +
|
||||
`Driver utilisé : ${driver}\n` +
|
||||
`Date : ${new Date().toISOString()}\n\n` +
|
||||
`— L'équipe Rubis`
|
||||
)
|
||||
if (this.replyTo) m.replyTo(this.replyTo)
|
||||
})
|
||||
|
||||
this.logger.success('Email envoyé')
|
||||
// Resend renvoie un messageId dans la réponse — utile pour retrouver
|
||||
// le log dans le dashboard.
|
||||
if (response?.messageId) {
|
||||
this.logger.info(`messageId: ${response.messageId}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user