Skip to content

pimalaya/io-smtp

I/O SMTP Documentation Matrix Mastodon

I/O-free SMTP client library written in Rust.

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::{io::{Read, Write}, net::TcpStream};

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

let mut stream = TcpStream::connect("smtp.example.com:25").unwrap();
let domain = Domain::parse(b"localhost").unwrap();
let mut buf = [0u8; 4096];

// Read greeting
let mut coroutine = GetSmtpGreeting::new();
let mut chunk: Vec<u8>;
let mut arg: Option<&[u8]> = None;

loop {
    match coroutine.resume(arg.take()) {
        GetSmtpGreetingResult::Ok { .. } => break,
        GetSmtpGreetingResult::WantsRead => {
            let n = stream.read(&mut buf).unwrap();
            chunk = buf[..n].to_vec();
            arg = Some(&chunk);
        }
        GetSmtpGreetingResult::Err(err) => panic!("{err}"),
    }
}

// Send EHLO
let mut coroutine = SmtpEhlo::new(domain.into());
let mut chunk: Vec<u8>;
let mut arg: Option<&[u8]> = None;

let capabilities = loop {
    match coroutine.resume(arg.take()) {
        SmtpEhloResult::Ok { capabilities, .. } => break capabilities,
        SmtpEhloResult::WantsWrite(bytes) => stream.write_all(&bytes).unwrap(),
        SmtpEhloResult::WantsRead => {
            let n = stream.read(&mut buf).unwrap();
            chunk = buf[..n].to_vec();
            arg = Some(&chunk);
        }
        SmtpEhloResult::Err(err) => panic!("{err}"),
    }
};

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

Send a message via SMTP

use std::{io::{Read, Write}, net::TcpStream};

use io_smtp::send::{SmtpMessageSend, SmtpMessageSendResult};
use io_smtp::rfc5321::types::{forward_path::ForwardPath, reverse_path::ReversePath};

let mut stream = TcpStream::connect("smtp.example.com:25").unwrap();
let mut buf = [0u8; 4096];

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 chunk: Vec<u8>;
let mut arg: Option<&[u8]> = None;

loop {
    match coroutine.resume(arg.take()) {
        SmtpMessageSendResult::Ok => break,
        SmtpMessageSendResult::WantsWrite(bytes) => stream.write_all(&bytes).unwrap(),
        SmtpMessageSendResult::WantsRead => {
            let n = stream.read(&mut buf).unwrap();
            chunk = buf[..n].to_vec();
            arg = Some(&chunk);
        }
        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