#imap #type #data-structures

imap-types

Misuse-resistant data structures for IMAP

8 releases (1 stable)

1.0.0 Aug 22, 2023
1.0.0-beta Aug 17, 2023
0.10.0 Jul 5, 2023
0.9.0 May 30, 2023
0.5.0 Jun 8, 2022

#38 in Email

Download history 45/week @ 2024-01-14 23/week @ 2024-01-21 13/week @ 2024-01-28 37/week @ 2024-02-04 64/week @ 2024-02-11 54/week @ 2024-02-18 47/week @ 2024-02-25 48/week @ 2024-03-03 53/week @ 2024-03-10 42/week @ 2024-03-17 42/week @ 2024-03-24 83/week @ 2024-03-31 82/week @ 2024-04-07 51/week @ 2024-04-14 38/week @ 2024-04-21 60/week @ 2024-04-28

246 downloads per month
Used in 2 crates (via imap-codec)

MIT/Apache

340KB
5.5K SLoC

imap-types

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 a complete codec implementation, i.e., parsers, serializers, and network support, 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, Atom, IString, Quoted, and 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 ...

Command::new(
    "A1",
    CommandBody::login("alice", "password").unwrap(),
).unwrap();

... will produce ...

A1 LOGIN alice password

However, ...

Command::new(
    "A1",
    CommandBody::login("alice\"", b"\xCA\xFE".as_ref()).unwrap(),
)
.unwrap();

... will produce ...

A1 LOGIN "alice\"" {2}
\xCA\xFE

Also, the construction ...

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 ...

Command::new(
    "A1",
    CommandBody::login(Literal::try_from("alice").unwrap(), "password").unwrap(),
)
.unwrap();

... to produce ...

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:

// This could be provided by the email application.
let tag = TagGenerator::random();

Command {
    tag,
    body: CommandBody::Login {
        // Note that the "unvalidated" feature must be activated.
        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.

Dependencies

~1.5–2.3MB
~43K SLoC