FakeSMTP

FakeSMTP est un serveur SMTP. On peut lui envoyer des e-mails mais il ne les transmet jamais aux destinataires. Il les stocke dans un répertoire local sous forme de fichiers .eml.

On l’utilise généralement en environnement de développement ou en test d’intégration.

Docker

Il existe plusieurs logiciels qui répondent au nom de FakeSMTP. Celui que j’utilise est développé par Gautier Mechling, en Java.

Le développement a commencé en 2011, jusqu’en 2015. Depuis, la maintenance est ralentie. Mais je ne pense pas que ça pose de problème. Il tourne bien sur un JDK 11, preuve qu’il vieillit bien.

Image Docker

Avant j’utilisais l’image munkyboy/fakesmtp, mais elle fonctionne avec un JDK 7 et n’a jamais été mise à jour. Depuis, je suis passé sur ghusta/fakesmtp dont la dernière version tourne sur un JDK 11.

docker run --publish 127.0.0.1:2025:25 --detach ghusta/fakesmtp
Le conteneur fonctionne en root, mais je n’ai pas trouvé d’équivalent avec un user.

Volume

Pour accéder aux fichiers .eml des messages, il faut monter un volume en répertoire local.

docker run --publish 127.0.0.1:2025:25 --volume /tmp/smtp:/var/mail --detach ghusta/fakesmtp

Docker Compose

  smtp:
    image: ghusta/fakesmtp
    ports:
      - "127.0.0.1:2025:25"
    volumes:
      - "/tmp/smtp:/var/mail"

Dans les tests

Ça peut aussi se démarrer avec Testcontainer pour des tests d’intégration automatisés.

  GenericContainer<?> smtp = new GenericContainer<>("ghusta/fakesmtp")
                                        .withExposedPorts(25);
  smtp.start();

  int smtpPort = smtp.getMappedPort(25);

Lecture des messages

Pour lire les fichiers eml, on peut utiliser l’API Jakarta Mail, anciennement _Java Mail. La principipale classe est MimeMessage, elle permet d’accéder aux données et métadonnées d’un message.

Pour avoir un tel objet, il faut ouvrir un IntputStream sur le fichier .eml et le passer en paramètre du contructeur.

    InputStream is = Files.newInputStream(emlPath);
    Session session = Session.getDefaultInstance(new Properties());
    MimeMessage message = new MimeMessage(session, is);
    // ...
  • MimeMessage

    • parse()

    • getFrom(): Address[]

    • getReplyTo(): Address[]

    • getRecipients(Message.RecipientType type): Address[]

    • getSubject(): String

    • getContent(): Object

L’API standard n’étant pas très amicale, je préfère encapsuler l’objet dans un EmailWrapper :

  • plutôt que de retourner des Address, je manipule des String,

  • les méthodes sont susceptibles de lever des MessagingException qui sont checked,

  • le contenu peut être multipart qui doit être décortiqué.

Apache Commons Mail a une classe MimeMessageParser qui facilite aussi la manipulation de MimeMessage. Cette classe a quand même un gros défaut, ses méthodes sont susceptibles de lever une Exception, sans autre précision.

  • MimeMessageParser

    • parse()

    • getFrom(): String

    • getReplyTo(): String

    • getTo(): List<Address>

    • getCc(): List<Address>

    • getBcc(): List<Address>

    • getSubject(): String

    • getHtmlContent(): String

    • getPlainContent(): String

Spring Framework a une classe MimeMessageHelper qui facilite aussi la manipulation de MimeMessage, mais qui est beaucoup plus orientée sur l’écriture d’un message que sur sa lecture.