Skip to content

pimalaya/pimconf

🪄 Pimconf Documentation Matrix Mastodon

CLI and lib to discover PIM-related services, written in Rust.

This repository ships three things:

  • Low-level I/O-free coroutines (no_std state machines that emit read/write requests)
  • Mid-level clients, based on coroutines (standard, blocking)
  • High-level CLI, based on std clients

Table of contents

Features

  • Mozilla Thunderbird Autoconfiguration support wiki (requires autoconfig feature):
    • ISP main and /.well-known/ URL lookups
    • Thunderbird ISPDB lookup
    • DNS MX-based retry against the MX target's parent domain
    • DNS TXT mailconf=<URL> redirect
  • RFC 6186 SRV discovery support (requires rfc6186 feature):
    • _imap._tcp, _imaps._tcp, _submission._tcp assembly into a single report
  • PACC discovery support draft-ietf-mailmaint-pacc-02 (requires pacc feature):
    • Well-known JSON configuration fetch
    • SHA-256 digest verification against the _ua-auto-config TXT record
  • TLS support:
    • Rustls with ring crypto (requires rustls-ring feature)
    • Rustls with aws crypto (requires rustls-aws feature)
    • Native TLS (requires native-tls feature)
  • JSON output via --json

Tip

pimconf is written in Rust and uses cargo features to gate functionality. The default feature set is declared in Cargo.toml.

Installation

Pre-built binary

The CLI binary pimconf has not been officially released yet. Check the releases GitHub workflow and look for the Artifacts section. These pre-built binaries are built from the master branch.

Note

Pre-built binaries are built with the default cargo features, plus cli. If you need more features, please use another installation method.

Cargo

cargo install pimconf --locked

You can also use the git repository for a more up-to-date (but less stable) version:

cargo install --locked --git https://github.com/pimalaya/pimconf.git

To use pimconf as a library, add it to your Cargo.toml:

[dependencies]
pimconf = { version = "0.0.1", default-features = false, features = ["autoconfig", "pacc", "rfc6186", "client"] }

The client feature pulls in the std-blocking helpers. Drop it (and pick any combination of autoconfig / pacc / rfc6186) for a no_std-friendly, pure-coroutine build.

Nix

If you have the Flakes feature enabled:

nix profile install github:pimalaya/pimconf

Or run without installing:

nix run github:pimalaya/pimconf -- autoconfig <local-part> <domain>

Sources

git clone https://github.com/pimalaya/pimconf
cd pimconf
nix run

Usage

Library

Using a low-level DNS MX I/O-free coroutine:

use std::{io::{Read, Write}, net::TcpStream};
use pimconf::autoconfig::mx::{DiscoveryDnsMx, DiscoveryDnsMxResult};
use url::Url;

let resolver = Url::parse("tcp://1.1.1.1:53").unwrap();
let mut stream = TcpStream::connect("1.1.1.1:53").unwrap();
let mut coroutine = DiscoveryDnsMx::new("fastmail.com", resolver);
let mut buf = [0u8; 4096];
let mut arg: Option<&[u8]> = None;

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

for record in records {
    println!("- {} {}", record.rdata.preference.get(), record.rdata.exchange);
}

Using a mid-level std PACC client:

use pimconf::pacc::client::DiscoveryPaccClientStd;
use pimalaya_stream::tls::Tls;
use url::Url;

let dns = Url::parse("tcp://1.1.1.1:53").unwrap();
let mut client = DiscoveryPaccClientStd::new(dns).with_tls(Tls::default());

let config = client.discover("fastmail.com").unwrap();
println!("{config:#?}");

CLI

Run the full Thunderbird Autoconfiguration chain on <local_part> <domain>:

pimconf autoconfig user fastmail.com

The chain tries, in order: every ISP main URL (secure then plain), every /.well-known/ URL (secure then plain), the Thunderbird ISPDB, then re-tries the same against the MX target's parent domain, then logs the mailconf=<URL> TXT redirect if one is published.

Run a single primitive instead:

pimconf autoconfig user fastmail.com isp --secure
pimconf autoconfig user fastmail.com isp-fallback --secure
pimconf autoconfig user fastmail.com ispdb --secure
pimconf autoconfig user fastmail.com mx
pimconf autoconfig user fastmail.com mailconf

Run RFC 6186 SRV discovery (top-level subcommand):

pimconf srv fastmail.com

Run PACC discovery:

pimconf pacc fastmail.com

JSON output:

pimconf --json autoconfig user fastmail.com

Pick a specific TLS stack and crypto provider:

pimconf --tls rustls --rustls-crypto ring autoconfig user fastmail.com
pimconf --tls native-tls pacc fastmail.com
pimconf --tls-cert /path/to/extra-root.pem autoconfig user fastmail.com

FAQ

How to debug the CLI?

Use --log <level> where <level> is one of off, error, warn, info, debug, trace:

pimconf --log trace autoconfig user fastmail.com

The RUST_LOG environment variable, when set, overrides --log and supports per-target filters (see the env_logger documentation). RUST_BACKTRACE=1 enables full error backtraces.

Logs are written to stderr, so they can be redirected easily to a file:

pimconf --log trace autoconfig user fastmail.com 2>/tmp/pimconf.log

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