Skip to content

pimalaya/io-smtp

I/O SMTP Documentation Matrix Mastodon

I/O-free SMTP client library written in Rust, based on io-socket

Table of contents

RFC coverage

This library implements SMTP as I/O-agnostic coroutines — no sockets, no async runtime, no std required.

Module What it covers
login LOGIN — legacy de-facto AUTH mechanism (no RFC)
1870 SIZE — maximum message size declaration
3207 STARTTLS — upgrade a plain connection to TLS
3461 DSN — RET, ENVID, NOTIFY, ORCPT ESMTP parameters for MAIL FROM / RCPT TO
3463 Enhanced status codes — EnhancedStatusCode type
4616 PLAIN — SASL PLAIN authentication mechanism
4954 AUTH — SASL exchange protocol
5321 SMTP — greeting, EHLO, HELO, MAIL FROM, RCPT TO, DATA, NOOP, RSET, QUIT
7628 OAUTHBEARER — OAuth 2.0 bearer token SASL mechanism
7677 SCRAM-SHA-256 — SASL SCRAM-SHA-256 mechanism (feature scram)

Examples

Send EHLO via SMTP (blocking)

use std::net::TcpStream;

use io_smtp::rfc5321::{
    ehlo::{SmtpEhlo, SmtpEhloResult},
    greeting::{GetSmtpGreeting, GetSmtpGreetingResult},
    types::domain::Domain,
};
use io_socket::runtimes::std_stream::handle;

let mut stream = TcpStream::connect("smtp.example.com:25").unwrap();
let domain = Domain::parse(b"localhost").unwrap();

// Read greeting
let mut coroutine = GetSmtpGreeting::new();
let mut arg = None;

loop {
    match coroutine.resume(arg.take()) {
        GetSmtpGreetingResult::Ok { .. } => break,
        GetSmtpGreetingResult::Io { input } => arg = Some(handle(&mut stream, input).unwrap()),
        GetSmtpGreetingResult::Err { err } => panic!("{err}"),
    }
}

// Send EHLO
let mut coroutine = SmtpEhlo::new(domain.into());
let mut arg = None;

let capabilities = loop {
    match coroutine.resume(arg.take()) {
        SmtpEhloResult::Ok { capabilities } => break capabilities,
        SmtpEhloResult::Io { input } => arg = Some(handle(&mut stream, input).unwrap()),
        SmtpEhloResult::Err { err } => panic!("{err}"),
    }
};

println!("Server capabilities: {capabilities:?}");

Send a message via SMTP (async)

use io_smtp::send::{SmtpMessageSend, SmtpMessageSendResult};
use io_smtp::rfc5321::types::{forward_path::ForwardPath, reverse_path::ReversePath};
use io_socket::runtimes::tokio_stream::handle;
use tokio::net::TcpStream;

let mut stream = TcpStream::connect("smtp.example.com:25").await.unwrap();

let from: ReversePath = "<sender@example.com>".parse().unwrap();
let to: ForwardPath = "<recipient@example.com>".parse().unwrap();
let message = b"From: sender@example.com\r\nTo: recipient@example.com\r\nSubject: Test\r\n\r\nHello!".to_vec();

let mut coroutine = SmtpMessageSend::new(from, [to], message);
let mut arg = None;

loop {
    match coroutine.resume(arg.take()) {
        SmtpMessageSendResult::Ok => break,
        SmtpMessageSendResult::Io { input } => arg = Some(handle(&mut stream, input).await.unwrap()),
        SmtpMessageSendResult::Err { err } => panic!("{err}"),
    }
}

See complete examples at ./examples.

More examples

Have a look at projects built on top of this library:

License

This project is licensed under either of:

at your option.

Social

Sponsoring

nlnet

Special thanks to the NLnet foundation and the European Commission that have been financially supporting the project for years:

If you appreciate the project, feel free to donate using one of the following providers:

GitHub Ko-fi Buy Me a Coffee Liberapay thanks.dev PayPal

About

I/O-free SMTP client library written in Rust

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Contributing

Stars

Watchers

Forks

Contributors

Languages