NodeJS + Serveur SMTP

TG
  • Tommy Gingras
    Studio Webux S.E.N.C
    1 Avril 2020

Introduction

L’objectif de cet article est de créer un serveur SMTP (serveur de courriel) avec NodeJS.

L’utilité de ce projet est de permettre de faire des tests rapidement avec les courriels dans un environnement de développement.
De plus, cette technique permet de recevoir des courriels, de les analyser et de les traiter de plusieurs manières et le tout en JavaScript.

Le package NPM utilisé pour atteindre cet objectif est celui de nodemailer soit smtp-server

Matériel requis

  • NodeJS
  • NPM
  • Connaissance en serveur SMTP / ce qui se rapporte aux courriels

Étape 1 - Création du Projet

mkdir smtp && cd smtp
npm init

npm install --save smtp-server

Étape 2 - Création du fichier serveur

À la racine du projet, créer un fichier nommé server.js

Ajouter ceci dans le fichier (proviens directement de l’exemple disponible sur Github)

// smtp.js
const { SMTPServer } = require("smtp-server");

const server = new SMTPServer({
  // disable STARTTLS to allow authentication in clear text mode
  disabledCommands: ["STARTTLS", "AUTH"],
  logger: true,
  onData(stream, session, callback) {
    stream.pipe(process.stdout); // print message to console
    stream.on("end", callback);
  },
});

server.listen(2525);

Le port 2525 a été utilisé pour faire les tests, car le port 25 était déjà utilisé par le service postfix.

Le port 2525 et NodeJS

Source: issue Github

Pour autoriser le port 2525 dans NodeJS, il faut exécuter la commande node en sudo, ce qui n’est pas du tout recommandé.

ou faire comme suit pour utiliser le port 25:

sudo setcap 'cap_net_bind_service=+ep' /usr/bin/node
sudo kill -9 `sudo lsof -t -i:25`

Étape 3 - Envoyer un courriel

Ouvrir un autre terminal (Sur la même machine)

Puis lancez cette commande :

Vous devez avoir netcat sur votre machine

nc localhost 2525

Puis vous pouvez utiliser les commandes suivantes:

helo localhost
mail from: <test@localhost>
rcpt to: <test@localhost>
data
Subject: Un test
Du contenu
^M
.^M
quit

Sur le MacBook, afficher les caractères <CR><LF> ou ^M, il faut faire control+v, ENTER, ENTER

Pour terminer d’écrire le corps du message (body),

^M
.^M

La sortie sur la console obtenue:

someuser@MacBook ~ % nc localhost 2525
220 MacBook.local ESMTP
helo localhost
250 MacBook.local Nice to meet you, mail.local
mail from: <test@localhost>
250 Accepted
rcpt to: <test@localhost>
250 Accepted
data
354 End data with <CR><LF>.<CR><LF>
Subject: Testing email with nodejs
Some content
^M
.^M
250 OK: message queued
quit
221 Bye

Étape 4 - Sur la console du serveur

someuser@MacBook Tools % sudo node index.js
Password:
[2020-04-02 02:28:35] INFO SMTP Server listening on [::]:2525
[2020-04-02 02:28:50] INFO [#tdl2lpomj6hycbca] Connection from mail.local
[2020-04-02 02:28:50] DEBUG [#tdl2lpomj6hycbca] S: 220 MacBook ESMTP
[2020-04-02 02:28:55] DEBUG [#tdl2lpomj6hycbca] C: helo localhost
[2020-04-02 02:28:55] DEBUG [#tdl2lpomj6hycbca] S: 250 MacBook Nice to meet you, mail.local
[2020-04-02 02:29:14] DEBUG [#tdl2lpomj6hycbca] C: mail from: <test@localhost>
[2020-04-02 02:29:14] DEBUG [#tdl2lpomj6hycbca] S: 250 Accepted
[2020-04-02 02:29:23] DEBUG [#tdl2lpomj6hycbca] C: rcpt to: <test@localhost>
[2020-04-02 02:29:23] DEBUG [#tdl2lpomj6hycbca] S: 250 Accepted
[2020-04-02 02:29:25] DEBUG [#tdl2lpomj6hycbca] C: data
[2020-04-02 02:29:25] DEBUG [#tdl2lpomj6hycbca] S: 354 End data with <CR><LF>.<CR><LF>
Subject: Testing email with nodejs
Some content

.

[2020-04-02 02:30:26] DEBUG [#tdl2lpomj6hycbca] C: <73 bytes of DATA>
[2020-04-02 02:30:26] DEBUG [#tdl2lpomj6hycbca] S: 250 OK: message queued
2020-04-02 02:30:59] DEBUG [#tdl2lpomj6hycbca] C: quit
[2020-04-02 02:30:59] DEBUG [#tdl2lpomj6hycbca] S: 221 Bye
[2020-04-02 02:30:59] INFO [#tdl2lpomj6hycbca] Connection closed to mail.local

Vous devriez avoir obtenu quelque chose semblable.

Étape 5 - Autres trucs et intégrations

Nodemailer offre un outil en NodeJS pour envoyer les courriels,

smtp-connection

Voici un exemple:

npm install nodemailer --save

Créer un fichier nommé client.js

const SMTPConnection = require("nodemailer/lib/smtp-connection");

let connection = new SMTPConnection({
  port: 2525,
  host: "127.0.0.1",
  secure: false,
  debug: true,
});

connection.connect(() => {
  console.log("Connection is established");
});

connection.on("connect", () => {
  console.log("Client Connected");
  connection.send(
    { from: "test@location.com", to: "testing@somewhere.com" },
    "Subject: This is the subject\nThis is my message for you, HELLO !",
    (err, info) => {
      console.error(err);
      console.log(info);
    }
  );
});

connection.on("error", (err) => {
  console.error(err);
});

Lancer la commande comme suit : node client.js

La sortie sur la console du fichier client.js

Connection is established
Client Connected
null
{ accepted: [ 'testing@somewhere.com' ],
rejected: [],
envelopeTime: 4,
messageTime: 5,
messageSize: 70,
response: '250 OK: message queued' }

La sortie du serveur

2020-04-02 02:49:55] INFO [#hmfejvebjflwu4ep] Connection from mail.local
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] S: 220 MacBook.local ESMTP
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] C: EHLO MacBook.local
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] S: 250-MacBook.local Nice to meet you, mail.local
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] 250-PIPELINING
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] 250-8BITMIME
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] 250 SMTPUTF8
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] C: MAIL FROM:<test@location.com>
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] S: 250 Accepted
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] C: RCPT TO:<testing@somewhere.com>
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] S: 250 Accepted
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] C: DATA
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] S: 354 End data with <CR><LF>.<CR><LF>
Subject: This is the subject
This is my message for you, HELLO !
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] C: <67 bytes of DATA>
[2020-04-02 02:49:55] DEBUG [#hmfejvebjflwu4ep] S: 250 OK: message queued
[2020-04-02 02:50:55] DEBUG [#hmfejvebjflwu4ep] S: 421 Timeout - closing connection
[2020-04-02 02:50:55] INFO [#hmfejvebjflwu4ep] Connection closed to mail.local

Conclusion

Ce petit projet m’a permis d’apprendre les commandes pour envoyer un serveur et ce type de serveur m’a permis de faire une démo pour mon module @studiowebux/mailer

La démo est disponible : mailer

Problèmes survenus

501 Bad sender address syntax

Il me manquait les < et >

mail from: <test@something.com>
rcpt to: <test@somewhere.com>

Port déjà utilisé

Vérifier que votre port 25 est disponible (j’utilise le port 2525 pour éviter les conflits)

Aucun email n’est envoyé

C’est normal, vous devez gérer cette partie pour envoyer le email. C’est-à-dire que vous devez renvoyer le courriel sur un “vrai” serveur de courriel.

421 Timeout - closing connection

Il faut utiliser la commande quit pour terminer la connexion avant le timeout.