Bibliothèque lettre pour Rust : envoyer des emails
1. Qu'est-ce que c'est et pourquoi l'utiliser
lettre (du français "lettre") est une bibliothèque puissante, asynchrone et typée pour envoyer des emails en Rust. Elle offre un ensemble complet d'outils pour créer et envoyer des messages électroniques, prenant en charge aussi bien les emails texte simples que les emails HTML complexes avec pièces jointes. La bibliothèque est écrite en Rust pur, sans dépendances système externes, ce qui en fait un choix idéal pour les projets où la portabilité et la sécurité sont essentielles.
Pourquoi utiliser lettre ? Dans le développement web moderne, l'envoi d'emails reste une fonctionnalité cruciale : inscription des utilisateurs, réinitialisation de mots de passe, notifications, newsletters. Rust, en tant que langage système, ne disposait pas traditionnellement d'outils pratiques pour la gestion des emails. lettre comble ce vide en proposant une API élégante, une prise en charge complète des normes SMTP, MIME et SSL/TLS, ainsi qu'une intégration avec les runtimes asynchrones populaires (tokio, async-std).
Les fonctionnalités clés de la bibliothèque incluent : la prise en charge de SMTP, SMTPS et SMTP via STARTTLS ; la création de messages MIME multipart avec pièces jointes ; la gestion des parties HTML et texte ; l'envoi asynchrone ; l'encodage automatique des pièces jointes et des en-têtes ; ainsi qu'une sécurité de typage totale à la compilation, ce qui évite de nombreuses erreurs courantes dans les langages dynamiques.
2. Installation
Pour installer la bibliothèque lettre, ajoutez-la dans le fichier Cargo.toml de votre projet :
[dependencies]
lettre = "0.11"
Pour une utilisation asynchrone avec tokio (recommandé) :
[dependencies]
lettre = { version = "0.11", features = ["tokio1-rustls-tls", "builder"] }
tokio = { version = "1", features = ["full"] }
Pour une utilisation synchrone (sans runtime asynchrone) :
[dependencies]
lettre = { version = "0.11", features = ["rustls-tls", "builder"] }
Après avoir ajouté les dépendances, exécutez la commande :
cargo build
3. Démarrage rapide
Un exemple minimal fonctionnel pour envoyer un email via le serveur SMTP de Gmail :
use lettre::message::header::ContentType;
use lettre::transport::smtp::authentication::Credentials;
use lettre::{Message, SmtpTransport, Transport};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Création du message
let email = Message::builder()
.from("Expéditeur <your_email@gmail.com>".parse()?)
.to("Destinataire <recipient@example.com>".parse()?)
.subject("Bonjour depuis Rust !")
.header(ContentType::TEXT_PLAIN)
.body("Ceci est un email de test envoyé avec lettre.".to_string())?;
// Configuration du transport SMTP
let creds = Credentials::new(
"your_email@gmail.com".to_string(),
"your_app_password".to_string() // Utilisez un mot de passe d'application
);
let mailer = SmtpTransport::relay("smtp.gmail.com")?
.credentials(creds)
.build();
// Envoi
match mailer.send(&email) {
Ok(_) => println!("Email envoyé avec succès !"),
Err(e) => eprintln!("Erreur d'envoi : {:?}", e),
}
Ok(())
}
4. Méthodes et structures principales
4.1. Message::builder()
Signature : pub fn builder() -> MessageBuilder
Description : Crée un nouveau builder pour construire un message email. Le builder permet de définir en chaîne tous les paramètres du message : expéditeur, destinataires, sujet, contenu et en-têtes.
use lettre::Message;
let email = Message::builder()
.from("user@example.com".parse()?)
.to("recipient@example.com".parse()?)
.subject("Test")
.body("Bonjour !".to_string())?;
4.2. MessageBuilder::to()
Signature : pub fn to(self, addr: Address) -> MessageBuilder
Description : Ajoute un destinataire principal (champ "To") au message. Peut être appelé plusieurs fois pour ajouter plusieurs destinataires.
let email = Message::builder()
.from("moi@example.com".parse()?)
.to("ami1@example.com".parse()?)
.to("ami2@example.com".parse()?)
.subject("Salut à tous")
.body("Message de groupe !".to_string())?;
4.3. MessageBuilder::subject()
Signature : pub fn subject(self, subject: &str) -> MessageBuilder
Description : Définit le sujet de l'email. Accepte une chaîne de caractères qui sera automatiquement encodée si nécessaire.
let email = Message::builder()
.from("contact@example.com".parse()?)
.to("client@example.com".parse()?)
.subject("Votre commande est confirmée")
.body("Merci pour votre achat !".to_string())?;
4.4. SmtpTransport::relay()
Signature : pub fn relay(relay: &str) -> Result
Description : Crée un transport SMTP en spécifiant le serveur relais (par exemple "smtp.gmail.com"). Retourne un builder pour configurer l'authentification et les options de sécurité.
use lettre::transport::smtp::authentication::Credentials;
let creds = Credentials::new("user@example.com".to_string(), "password".to_string());
let mailer = SmtpTransport::relay("smtp.example.com")?
.credentials(creds)
.build();
4.5. SmtpTransport::send()
Signature : pub fn send(&self, message: &Message) -> Result
Description : Envoie le message via le transport SMTP configuré. Retourne l'adresse email de l'expéditeur en cas de succès.
match mailer.send(&email) {
Ok(addr) => println!("Email envoyé depuis : {}", addr),
Err(e) => eprintln!("Échec de l'envoi : {}", e),
}
5. Exemples avancés
5.1. Email HTML avec pièce jointe
use lettre::message::header::ContentType;
use lettre::message::{Attachment, MultiPart, SinglePart};
use lettre::{Message, SmtpTransport, Transport};
let email = Message::builder()
.from("expediteur@example.com".parse()?)
.to("destinataire@example.com".parse()?)
.subject("Rapport mensuel")
.multipart(
MultiPart::mixed()
.singlepart(
SinglePart::builder()
.header(ContentType::TEXT_HTML)
.body(String::from(
"<h1>Rapport mensuel</h1><p>Veuillez trouver ci-joint le rapport.</p>"
)),
)
.singlepart(
Attachment::new("rapport.pdf".to_string())
.body(std::fs::read("rapport.pdf")?, ContentType::parse("application/pdf")?),
),
)?;
5.2. Envoi asynchrone avec tokio
use lettre::message::header::ContentType;
use lettre::transport::smtp::authentication::Credentials;
use lettre::{AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let email = Message::builder()
.from("expediteur@example.com".parse()?)
.to("destinataire@example.com".parse()?)
.subject("Email asynchrone")
.header(ContentType::TEXT_PLAIN)
.body("Envoyé de manière asynchrone avec tokio !".to_string())?;
let creds = Credentials::new(
"expediteur@example.com".to_string(),
"mot_de_passe".to_string(),
);
let mailer = AsyncSmtpTransport::<Tokio1Executor>::relay("smtp.example.com")?
.credentials(creds)
.build();
match mailer.send(email).await {
Ok(_) => println!("Email envoyé avec succès !"),
Err(e) => eprintln!("Erreur : {:?}", e),
}
Ok(())
}
6. Bonnes pratiques et astuces
- Utilisez des mots de passe d'application pour Gmail et autres services qui exigent une authentification à deux facteurs.
- Préférez l'envoi asynchrone avec tokio pour les applications web, afin de ne pas bloquer le thread principal.
- Validez toujours les adresses email avant de les utiliser dans le builder pour éviter les erreurs à l'exécution.
- Utilisez des templates HTML pour les emails professionnels, mais gardez toujours une version texte pour l'accessibilité.
- Testez en environnement de développement avec un serveur SMTP factice comme MailHog ou Mailpit.
7. Conclusion
lettre est une bibliothèque Rust complète et moderne pour l'envoi d'emails. Sa conception typée et asynchrone en fait un choix de premier ordre pour les applications Rust nécessitant des communications par email fiables et sécurisées. Que vous construisiez une API web, un service de notification ou un outil en ligne de commande, lettre vous offre la flexibilité et la puissance nécessaires.
Pour aller plus loin, consultez la documentation officielle et explorez les fonctionnalités avancées comme les signatures DKIM, les en-têtes personnalisés et l'intégration avec d'autres services SMTP.