# imap-types ```mermaid %%{init: {'theme': 'neutral' } }%% flowchart LR imap-types -.-> imap-codec imap-codec -.-> imap-next imap-next -.-> imap-proxy imap-next -.-> imap-client style imap-types stroke-width:4px click imap-types href "https://github.com/duesee/imap-codec/tree/main/imap-types" click imap-codec href "https://github.com/duesee/imap-codec" click imap-next href "https://github.com/duesee/imap-next" click imap-proxy href "https://github.com/duesee/imap-proxy" click imap-client href "https://github.com/soywod/imap-client" ``` This crate provides a complete set of well-designed, misuse-resistant types for the [IMAP4rev1] protocol and various [extensions]. Notably, it does *not* provide parsers, nor serializers, but tries to become the "standard library" for IMAP in Rust that is useful for a broad range of crates. If you are looking for parsers, and serializers, head over to [`imap-codec`]. ## Features * Rust's type system is used to enforce correctness and to make the library misuse-resistant. It's not possible to construct a message that violates the IMAP specification. * Fuzzing (via [cargo fuzz]) and property-based tests are used to uncover bugs. The library is fuzz-tested never to produce an invalid message. ## Working with imap-types To ensure correctness, imap-types makes use of types such as [`AString`](core::AString), [`Atom`](core::Atom), [`IString`](core::IString), [`Quoted`](core::Quoted), and [`Literal`](core::Literal). When constructing messages, imap-types can automatically choose the best representation. However, it's always possible to manually choose a specific representation. ### Examples
Automatic Construction This ... ```rust use imap_types::command::{Command, CommandBody}; let cmd = Command::new( "A1", CommandBody::login("alice", "password").unwrap() ).unwrap(); ``` ... will produce ... ```imap A1 LOGIN alice password ``` However, ... ```rust use imap_types::command::{Command, CommandBody}; let cmd = Command::new( "A1", CommandBody::login("alice\"", b"\xCA\xFE".as_ref()).unwrap(), ).unwrap(); ``` ... will produce ... ```imap A1 LOGIN "alice\"" {2} \xCA\xFE ``` Also, the construction ... ```rust,should_panic use imap_types::command::{Command, CommandBody}; let cmd = Command::new( "A1", CommandBody::login("alice\x00", "password").unwrap(), ).unwrap(); ``` ... will fail because IMAP doesn't allow NULL bytes in the username (nor password).
Manual Construction You can also use ... ```rust use imap_types::{ command::{Command, CommandBody}, core::Literal, }; let cmd = Command::new( "A1", CommandBody::login(Literal::try_from("alice").unwrap(), "password").unwrap(), ).unwrap(); ``` ... to produce ... ```imap A1 LOGIN {5} alice password ``` ... even though "alice" could be encoded more simply with an atom or quoted string. Also, you can use Rust literals and resort to `unvalidated` constructors when you are certain that your input is correct: ```rust use imap_types::{ command::{Command, CommandBody}, core::{AString, Atom, Tag}, secret::Secret, }; // This could be provided by the email application. struct TagGenerator; impl TagGenerator { fn random() -> Tag<'static> { // Make this random :-) Tag::unvalidated("A1") } } let tag = TagGenerator::random(); let cmd = Command { tag, body: CommandBody::Login { username: AString::from(Atom::unvalidated("alice")), password: Secret::new(AString::from(Atom::unvalidated("password"))), }, }; ``` In this case, imap-codec won't stand in your way. However, it won't guarantee that you produce correct messages, either.
# License This crate is dual-licensed under Apache 2.0 and MIT terms. [IMAP4rev1]: https://datatracker.ietf.org/doc/html/rfc3501 [extensions]: https://docs.rs/imap-codec/latest/imap_codec/#features [`imap-codec`]: https://docs.rs/imap-types/latest/imap_codec/ [cargo fuzz]: https://github.com/rust-fuzz/cargo-fuzz [core]: https://docs.rs/imap-types/latest/imap_types/core/index.html