pimconf 0.1.0

CLI and lib to discover PIM-related services
docs.rs failed to build pimconf-0.1.0
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

🪄 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 mail service discovery rfc6186 (requires rfc6186 feature):
    • _imap._tcp, _imaps._tcp, _submission._tcp assembly into a single report
  • RFC 6764 SRV CalDAV/CardDAV discovery rfc6764 (requires rfc6764 feature):
    • _caldav._tcp, _caldavs._tcp, _carddav._tcp, _carddavs._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.1", default-features = false, features = ["autoconfig", "pacc", "rfc6186", "rfc6764", "client"] }

The client feature pulls in the std-blocking helpers. Drop it (and pick any combination of autoconfig / pacc / rfc6186 / rfc6764) 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,
    coroutine::{DiscoveryCoroutine, DiscoveryCoroutineState, DiscoveryYield},
};
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()) {
        DiscoveryCoroutineState::Complete(Ok(records)) => break records,
        DiscoveryCoroutineState::Complete(Err(err)) => panic!("{err}"),
        DiscoveryCoroutineState::Yielded(DiscoveryYield::WantsWrite { bytes, .. }) => {
            stream.write_all(&bytes).unwrap();
        }
        DiscoveryCoroutineState::Yielded(DiscoveryYield::WantsRead { .. }) => {
            let n = stream.read(&mut buf).unwrap();
            arg = Some(&buf[..n]);
        }
    }
};

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 RFC 6764 CalDAV/CardDAV SRV discovery:

pimconf rfc6764 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

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.

AI disclosure

This project is developed with AI assistance. This section documents how, so users and downstream packagers can make informed decisions.

  • Tools: Claude Code (Anthropic), Opus 4.7, invoked locally with a persistent project-scoped memory and a small set of repo-specific rules.

  • Used for: Refactors, mechanical multi-file edits, boilerplate (feature gates, error enums, derive macros, trait impls), test scaffolding, doc polish, exploratory design conversations.

  • Not used for: Engineering, critical code, git manipulation (commit, merge, rebase…), real-world tests.

  • Verification: Every AI-assisted change is read, compiled, tested, and formatted before commit (nix develop --command cargo check / cargo test / cargo fmt). Behavioural correctness is verified against the relevant RFC or upstream spec, not assumed from the model output. Tests are never adjusted to fit AI-generated code; the code is adjusted to fit correct behaviour.

  • Limitations: AI models occasionally produce code that compiles and passes tests but is subtly wrong: off-by-one errors, missed edge cases, plausible but nonexistent APIs, stale RFC references. The verification workflow catches most of this; it does not catch all of it. Bug reports are welcome and taken seriously.

  • Last reviewed: 31/05/2026

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