marten-mail

Envoi des courriels par SMTP pour Marten, sans dépendance (client SMTP, messages MIME, backend Marten::Emailing)

= marten-mail :toc: :toc-title: Sommaire

Envoi des courriels par SMTP pour https://martenframework.com[Marten], sans dépendance : rien d'autre que la bibliothèque standard de Crystal.

== Pourquoi

Marten ne fournit en standard que son envoi de développement (Marten::Emailing::Backend::Development), qui garde les courriels en mémoire ou les affiche, mais n'envoie rien. Sans autre réglage, un projet en production perd tous ses courriels sans la moindre erreur (constaté sur l'administration de Partiduo, octobre 2026).

marten-mail fournit l'envoi réel, par un client SMTP écrit en Crystal (repris du transport des instances Partiduo) : pas de sendmail, pas de relais du serveur, pas de logiciel à installer. Chaque projet envoie avec son compte SMTP, distinct du relais système (alertes de monit…).

== Ce que contient le shard

  • MartenMail::Client : client SMTP minimal (EHLO, STARTTLS ou TLS direct, AUTH PLAIN, MAIL, RCPT, DATA, une connexion par message) ;
  • MartenMail::Message : message MIME (UTF-8, texte et/ou HTML, pièces jointes en base64, en-têtes encodés, aucune injection d'en-tête possible) ;
  • MartenMail::Backend : envoi des Marten::Email d'un projet par ce client.

require "marten-mail" charge le tout ; require "marten-mail/client" charge le client et le message sans Marten, pour un programme qui n'est pas une application Marten.

== Installation

[source,yaml]

dependencies: marten-mail: github: aloli-crystal/marten-mail branch: production

Le shard ne déclare aucune dépendance d'exécution : l'envoi pour Marten suppose que le projet dépend déjà de Marten.

== Utilisation avec Marten

[source,crystal]

require "marten-mail"

Marten.configure :production do |config| config.emailing.from_address = "notifications@example.net" config.emailing.backend = MartenMail::Backend.new(ENV["SMTP_URL"]) end

Tout Marten::Email du projet part alors par SMTP. Une adresse écrite "Nom <adresse>" (from "Partiduo <notifications@example.net>") est séparée en nom et adresse. Les copies cachées (bcc) ne servent qu'à l'enveloppe SMTP, jamais aux en-têtes. Un refus du serveur lève MartenMail::DeliveryError.

== Utilisation sans Marten

[source,crystal]

require "marten-mail/client"

client = MartenMail::Client.from_url(ENV["SMTP_URL"]) message = MartenMail::Message.new( from: "notifications@example.net", from_name: "Partiduo", to: ["client@example.org"], subject: "Bienvenue", text: "Bonjour…", html: "

Bonjour…

") message.reply_to = "contact@example.org" client.deliver(message)

== URL SMTP

[cols="3,4",options="header"] |=== |URL |Connexion

|smtp://utilisateur:secret@hôte:587 |Port 587, STARTTLS (défaut de smtp://)

|smtps://utilisateur:secret@hôte:465 |Port 465, TLS direct

|smtp://hôte:587?security=tls |TLS direct sur un autre port

|smtp://localhost:25?security=none |Sans chiffrement (relais local seulement)

|…?helo=serveur.example.net |Nom annoncé par EHLO (défaut : localhost) |===

L'identifiant et le secret sont encodés en URL : @ → %40, : → %3A, / → %2F, % → %25. Exemple : l'identifiant notifications@example.net s'écrit notifications%40example.net.

Sécurité. Un mot de passe n'est jamais envoyé en clair sur le réseau : avec security=none, l'authentification n'est acceptée que vers la machine elle-même (localhost, 127.0.0.1, ::1), et refusée avant toute connexion sinon. Le certificat du serveur est vérifié (STARTTLS et TLS direct). Les messages d'erreur reprennent la réponse du serveur, jamais le secret.

== Développement

[source,sh]

shards install crystal spec crystal tool format src spec

Les specs dialoguent avec un faux serveur SMTP local (spec/spec_helper.cr) ; elles n'envoient rien au dehors. Le shard est testé avec Crystal 1.21 et 1.22.

Le numéro de version est dans shard.yml seulement (lu par MartenMail::VERSION) ; chaque commit en relève le dernier chiffre.

Repository

marten-mail

Owner
Statistic
  • 0
  • 0
  • 0
  • 1
  • 1
  • about 6 hours ago
  • October 18, 2026
License

MIT License

Links
Synced at

Sun, 18 Oct 2026 08:42:32 GMT

Languages