L’envoi d’emails est une fonctionnalité incontournable dans le développement d’applications web. Qu’il s’agisse de notifications, de confirmations de commande ou de diagnostics avec images, NestJS propose des outils puissants pour gérer cela proprement.
Dans cet article, nous allons voir comment mettre en place une API d’envoi d’emails contenant des pièces jointes (fichiers multiples) en utilisant le module NestJS Mailer. Pour tester notre code en toute sécurité sans envoyer de vrais courriels, nous utiliserons Mailpit comme serveur SMTP local.
Dépendances à installer
Pour faire fonctionner cette API, vous devez installer le module officiel de configuration de NestJS, l’utilitaire d’envoi de mail, ainsi que Nodemailer qui gère le protocole de bas niveau. Les types pour Multer sont également requis pour éviter les erreurs TypeScript lors de la manipulation des fichiers.
Exécutez la commande suivante dans votre terminal :
npm install @nestjs/config @nestjs-modules/mailer nodemailer
npm install --save-dev @types/nodemailer @types/multer
Configuration de l’environnement
Avant de plonger dans le code NestJS, nous devons définir nos variables d’environnement. Créez un fichier
.env à la racine de votre projet. Ce fichier stockera l’adresse de l’expéditeur. Dans notre configuration locale avec Mailpit, le mot de passe reste vide.MAIL_USER=noreply@bricotips.local
MAIL_PASS=
Configuration globale de l’application
Le module principal
AppModule centralise la configuration. Nous y chargeons les variables d’environnement via ConfigModule et configurons le MailerModule de manière asynchrone pour injecter dynamiquement les configurations nécessaires.Voici le fichier
app.module.ts enrichi de commentaires explicatifs :import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MailModule } from './mail/mail.module';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { MailerModule } from '@nestjs-modules/mailer';
@Module({
imports: [
// Charge le fichier .env et rend les variables accessibles globalement dans l'application
ConfigModule.forRoot({
isGlobal: true,
}),
// Configuration asynchrone du module Mailer pour pouvoir injecter ConfigService
MailerModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
transport: {
host: '127.0.0.1', // Adresse IP locale de mon serveur Mailpit
port: 10016, // Port SMTP configuré par défaut sur Mailpit (local)
secure: false, // Pas de chiffrement SSL/TLS nécessaire pour le développement local
// Les identifiants sont commentés car Mailpit n'impose pas d'authentification par défaut
// auth:{
// user: config.get<string>('MAIL_USER'),
// pass: config.get<string>('MAIL_PASS')
// },
},
defaults: {
// Définition de l'expéditeur par défaut en utilisant la variable d'environnement
from: `"Mon partage sur l'envoie de mail " <${config.get<string>('MAIL_USER')}>`,
}
})
}),
// Importation du sous-module dédié à la gestion des mails
MailModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Le Service : Logique d’envoi de l’email
Le service
MailService est responsable de la composition de l’email. Il reçoit les données textuelles ainsi qu’un tableau de fichiers envoyé via la requête HTTP. Il transforme ensuite ces fichiers en pièces jointes standard pour le protocole SMTP.Voici le fichier
mail.service.ts :import { MailerService } from '@nestjs-modules/mailer';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import type {} from 'multer'; // Importation de type requise pour la prise en charge de Express.Multer.File
@Injectable()
export class MailService {
constructor(
// Injection du service de messagerie de NestJS et du gestionnaire de configuration
private readonly mailerService: MailerService,
private readonly configService: ConfigService
) {}
async sendMail(email: string, subject: string, content: string, images: Express.Multer.File[]) {
await this.mailerService.sendMail({
// Le destinataire est ici forcé sur l'adresse de l'administrateur définie dans le .env
to: this.configService.get<string>('MAIL_USER'),
subject: subject,
html: `
<p> ${content} </p>
`,
// Transformation du tableau de fichiers Multer en pièces jointes pour le mailer
attachments: images.map((image) => ({
filename: image.originalname, // Nom d'origine du fichier (ex: photo.jpg)
content: image.buffer, // Le contenu du fichier stocké temporairement en mémoire (Buffer)
contentType: image.mimetype // Le type de fichier (ex: image/jpeg, image/png)
}))
});
}
}
Le Contrôleur : Interception des fichiers et validation
Le rôle du contrôleur
MailController est de mettre à disposition un point d’accès (endpoint) HTTP POST. Il doit être capable d’intercepter des données textuelles en parallèle de fichiers physiques transférés via un formulaire multipart/form-data. NestJS utilise un intercepteur basé sur la bibliothèque Multer pour accomplir cela.Voici le fichier
mail.controller.ts :import { Body, Controller, Post, UploadedFiles, UseInterceptors, BadRequestException } from '@nestjs/common';
import { MailService } from './mail.service';
import { FilesInterceptor } from '@nestjs/platform-express';
@Controller('mail')
export class MailController {
constructor(
private readonly mailService: MailService
) {}
@Post()
// L'intercepteur FilesInterceptor extrait les fichiers nommés 'images' de la requête HTTP
@UseInterceptors(FilesInterceptor('images'))
sendMail(
// Récupération des champs textes du corps de la requête
@Body() body: { email: string, subject: string, content: string, images: string },
// Récupération du tableau de fichiers interceptés par Multer
@UploadedFiles() files: Array<Express.Multer.File>
) {
// Sécurité pour s'assurer que la variable est toujours un tableau, même si aucun fichier n'est transmis
const images = files ?? [];
// Validation métier : l'application exige la présence d'au moins une image (ex: pour un diagnostic)
if (images.length === 0) {
throw new BadRequestException('Au moins une image est obligatoire pour envoyer le diagnostic.');
}
// Transmission des données validées au service d'envoi
return this.mailService.sendMail(body.email, body.subject, body.content, images);
}
}
Tester l’API avec Mailpit
Pour tester cette API localement, vous devez avoir un serveur Mailpit en cours d’exécution sur votre machine. Mailpit agit comme un faux serveur SMTP. Il intercepte tous les messages sortants de votre application NestJS et vous permet de les consulter via une interface web agréable, sans jamais envoyer de vrais emails sur internet.
Une fois votre serveur NestJS démarré et Mailpit lancé, vous pouvez envoyer une requête POST de type
multipart/form-data vers http://localhost:3000/mail en utilisant un outil comme Postman ou Insomnia. Remplissez les champs email, subject, content, et ajoutez un ou plusieurs fichiers sous la clé images.En ouvrant l’interface graphique de Mailpit dans votre navigateur, vous verrez votre email apparaître instantanément avec toutes ses pièces jointes fonctionnelles.