@amsom-habitat/mailer-sender
v1.0.1
Published
Connecteur vers l'API Mail interne : envoi par template ou en corps libre, avec garde-fou anti-spam hors production (portage Node du package PHP amsom-habitat/mailer-sender).
Maintainers
Readme
@amsom-habitat/mailer-sender
Connecteur vers l'API Mail interne : envoi par template nommé ou en corps libre, garde-fou anti-spam hors production, erreurs typées.
Portage Node du package Composer amsom-habitat/mailer-sender.
Là où la version PHP s'appuyait sur MailerInterface/Twig de Symfony, cette version se contente d'appeler
l'API Mail en HTTP : aucune dépendance runtime, fetch natif (Node ≥ 18).
Installation
npm install @amsom-habitat/mailer-sender@nestjs/common est une peerDependency optionnelle, requise seulement pour le sous-export /nest.
Configuration
| Option | Type | Défaut | Rôle |
|---|---|---|---|
| baseUrl | string | — | base URL de l'API Mail, sans slash final (obligatoire) |
| env | string | undefined | tout ce qui n'est pas 'prod' active le garde-fou |
| devRecipient | string | [email protected] | destinataire de repli hors production |
| fetch | typeof fetch | globalThis.fetch | implémentation à utiliser (tests, proxy, instrumentation) |
| logger | { warn(msg) } | aucun | journal des réponses en erreur |
Garde-fou anti-spam
Hors production, tous les mails partent vers devRecipient — jamais vers le vrai destinataire. La règle
est dans le package précisément pour ne pas être réécrite (ni oubliée) dans chaque application :
new MailerSender({ baseUrl, env: 'prod' }).resolveRecipient('[email protected]') // [email protected]
new MailerSender({ baseUrl, env: 'dev' }).resolveRecipient('[email protected]') // [email protected]Un devRecipient défini mais vide retombe sur le défaut, plutôt que d'envoyer à une adresse vide.
Utilisation
Node « nu »
import { MailerSender } from '@amsom-habitat/mailer-sender'
const mailer = new MailerSender({
baseUrl: process.env.API_MAIL_URL!,
env: process.env.MAIL_ENV,
devRecipient: process.env.MAIL_DEV_RECIPIENT,
logger: console,
})
// 1. template nommé — POST {baseUrl}/send_prelevement_auto
await mailer.send('send_prelevement_auto', {
emailDestinataire: '[email protected]',
subject: 'Votre prélèvement automatique',
body: { nom: 'DUPONT', montant: '345,20 €' },
cc: '[email protected]',
})
// 2. corps libre — POST {baseUrl}/send_custom
await mailer.sendCustom({
emailDestinataire: '[email protected]',
subject: 'Suivi de votre demande',
body: { message: '<p>Votre demande a bien été enregistrée.</p>' },
templateConfig: { logo: 'logoAmsomEtMoi' },
})NestJS
// app.module.ts
import { MailerModule } from '@amsom-habitat/mailer-sender/nest'
@Module({
imports: [
MailerModule.forRootAsync({
isGlobal: true,
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
baseUrl: config.getOrThrow('API_MAIL_URL'),
env: config.get('MAIL_ENV'),
devRecipient: config.get('MAIL_DEV_RECIPIENT'),
}),
}),
],
})
export class AppModule {}import { MailService } from '@amsom-habitat/mailer-sender/nest'
@Injectable()
export class SollicitationService {
constructor(private readonly mail: MailService) {}
notifier(email: string, message: string) {
return this.mail.sendCustom({
emailDestinataire: email,
subject: 'Votre sollicitation',
body: { message },
})
}
}Payload envoyé
Les deux méthodes construisent le corps attendu par l'API Mail, avec les noms de champs de celle-ci
(sujet, attachement…). Les champs absents sont explicitement à null, comme le faisait la version PHP.
sendCustom ajoute le bloc de mise en forme, dont les défauts maison : logo: 'logoAmsomEtMoi',
bonjour: true, showFooter: true, showRemerciement: true. templateConfig permet de surcharger
n'importe lequel de ces réglages ; les autres gardent leur défaut.
Erreurs
| Cas | Erreur | status |
|---|---|---|
| API injoignable (échec réseau) | HttpClientError | 503 |
| Réponse non-2xx | HttpClientError | statut amont |
Le corps d'erreur renvoyé par l'API Mail est journalisé, jamais exposé : certaines API maison renvoient une trace complète qu'il ne faut pas laisser fuiter vers un client.
Côté NestJS, MailService traduit ces erreurs en exceptions Nest
(httpClientErrorToHttpException : 503 → ServiceUnavailableException, sinon HttpException du statut
amont). L'option mapError permet de fournir sa propre traduction.
API publique
@amsom-habitat/mailer-sender
| Export | Rôle |
|---|---|
| MailerSender | send(template, params), sendCustom(params), resolveRecipient(email) |
| HttpClientError | erreur d'appel (status, label, body) |
| fetchOk(url, init, label, deps?) | helper HTTP réutilisable pour d'autres clients d'API internes |
| MailerSenderOptions, MailResult, SendMailParams, SendMailCustomParams, TemplateConfig | types |
@amsom-habitat/mailer-sender/nest
| Export | Rôle |
|---|---|
| MailerModule.forRoot(options) / forRootAsync(options) | module fournissant MailService |
| MailService | version injectable, erreurs traduites en exceptions Nest |
| httpClientErrorToHttpException(err) | traduction par défaut |
| MAILER_MODULE_OPTIONS | jeton d'injection des options |
Développement
npm install
npm run build # tsc → dist/ (CommonJS + .d.ts)
npm run lint
npm test # jestLe package est publié en CommonJS : les API NestJS maison sont en CJS, un paquet ESM-only n'y serait
pas importable. La carte exports du package.json laisse la place à un build ESM ultérieur.
Versionnage
SemVer, une entrée par version dans changelog.md (## VX.Y.Z - JJ/MM/AAAA).
check-version.sh refuse une publication dont la version n'est pas décrite dans le changelog, ou qui porte
un suffixe de pré-release.
make publish # main : lint + build + test + check-version + tag git + npm publish
make alpha_publish # dev : publication d'une beta