Crate imap_types
source ·Expand description
Misuse-resistant Types for the IMAP Protocol
The main types in imap-types are Greeting, Command, and Response, and we use the term “message” to refer to either of them.
Module structure
The module structure reflects this terminology: types that are specific to commands are in the command module; types that are specific to responses (including the greeting) are in the response module; types used in both are in the message module. The codec module contains the Decode trait used to serialize messages. The core module contains “string types” – there should be no need to use them directly.
Simple construction of messages.
Messages can be created in different ways. However, what all ways have in common is, that the API does not allow the creation of invalid ones.
For example, all commands in IMAP (and many responses) are prefixed with a “tag”. Although IMAP tags are just strings, they have additional rules, such as that no whitespace is allowed. Thus, imap-codec encapsulates tags in the Tag struct and ensures no invalid tag can be created. This is why Result is often used in associated functions or methods.
Generally, imap-codec relies a lot on the From, TryFrom, Into, and TryInto traits. Make good use of them. For types that are more cumbersome to create, there are helper methods available.
Example
use std::convert::TryFrom;
use imap_types::{
    command::{Command, CommandBody},
    message::Tag,
};
// # Variant 1
// Create a `Command` with `tag` "A123" and `body` "NOOP".
// (Note: `Command::new()` returns `Result::Err(...)` when the tag is invalid.)
let cmd = Command::new("A123", CommandBody::Noop).unwrap();
// # Variant 2
// Create a `CommandBody` first and finalize it into
// a `Command` by attaching a tag later.
let cmd = CommandBody::Noop.tag("A123").unwrap();
// # Variant 3
// Create a `Command` directly.
let cmd = Command {
    tag: Tag::try_from("A123").unwrap(),
    body: CommandBody::Noop,
};Serialization of messages.
All messages implement the Encode trait.
You can use imap_types::Encode and call the .encode(...) (or .encode_detached(...)) method to serialize a message (into a writer).
Note that IMAP traces are not guaranteed to be UTF-8. Thus, be careful when using things like std::str::from_utf8(...).unwrap().
It should generally be better not to think about IMAP as being UTF-8.
This is also why Display is not implemented.
All types implement Debug, though.
Example
use imap_types::{
    codec::Encode,
    command::{Command, CommandBody},
};
// Create some command.
let cmd = Command::new("A123", CommandBody::login("alice", "password").unwrap()).unwrap();
// Encode the `cmd` into `out`.
let out = cmd.encode_detached().unwrap();
// Print the command.
// (Note that IMAP traces are not guaranteed to be valid UTF-8.)
println!("{}", std::str::from_utf8(&out).unwrap());More complex messages.
Example
The following example is a server fetch response containing the size and MIME structure of message 42.
use std::{borrow::Cow, convert::TryFrom, num::NonZeroU32};
use imap_types::{
    codec::Encode,
    core::{IString, NString, NonEmptyVec},
    response::{
        data::{
            BasicFields, Body, BodyStructure, FetchAttributeValue, SinglePartExtensionData,
            SpecificFields,
        },
        Data, Response,
    },
};
let fetch = {
    let data = Data::Fetch {
        seq_or_uid: NonZeroU32::new(42).unwrap(),
        attributes: NonEmptyVec::try_from(vec![
            FetchAttributeValue::Rfc822Size(1337),
            FetchAttributeValue::Body(BodyStructure::Single {
                body: Body {
                    basic: BasicFields {
                        parameter_list: vec![],
                        id: NString(None),
                        description: NString(Some(
                            IString::try_from("Important message.").unwrap(),
                        )),
                        content_transfer_encoding: IString::try_from("base64").unwrap(),
                        size: 512,
                    },
                    specific: SpecificFields::Basic {
                        type_: IString::try_from("text").unwrap(),
                        subtype: IString::try_from("html").unwrap(),
                    },
                },
                extension: Some(SinglePartExtensionData {
                    md5: NString(None),
                    disposition: None,
                    language: None,
                    location: None,
                    extension: Cow::Borrowed(b""),
                }),
            }),
        ])
        .unwrap(),
    };
    Response::Data(data)
};
let mut out = std::io::stdout();
fetch.encode(&mut out).unwrap();A Note on Types
Due to the correctness guarantees, this library uses multiple “string types” like Atom, Tag, NString, and IString. See the core module.
Modules
- Serialization of messages
 - Types used in commands
 - Core Data Types
 - Types used in commands and responses
 - Types used in responses
 - State and Flow Diagram