Crate jmap_client

source ·
Expand description

jmap-client

crates.io build docs.rs crates.io

jmap-client is a JSON Meta Application Protocol (JMAP) library written in Rust. The library is a full implementation of the JMAP RFCs including:

Features:

  • Async and blocking support (use the cargo feature blocking to enable blocking).
  • WebSocket async streams (use the cargo feature websockets to enable JMAP over WebSocket).
  • EventSource async streams.
  • Helper functions to reduce boilerplate code and quickly build JMAP requests.
  • Fast parsing and encoding of JMAP requests.

Usage Example

    // Connect to the JMAP server using Basic authentication.
    // (just for demonstration purposes, Bearer tokens should be used instead)
    let client = Client::new()
        .credentials(("john@example.org", "secret"))
        .connect("https://jmap.example.org")
        .await
        .unwrap();

    // Create a mailbox.
    let mailbox_id = client
        .mailbox_create("My Mailbox", None::<String>, Role::None)
        .await
        .unwrap()
        .take_id();

    // Import a message into the mailbox.
    client
        .email_import(
            b"From: john@example.org\nSubject: test\n\n test".to_vec(),
            [&mailbox_id],
            ["$draft"].into(),
            None,
        )
        .await
        .unwrap();

    // Obtain all e-mail ids matching a filter.
    let email_id = client
        .email_query(
            Filter::and([
                email::query::Filter::subject("test"),
                email::query::Filter::in_mailbox(&mailbox_id),
                email::query::Filter::has_keyword("$draft"),
            ])
            .into(),
            [email::query::Comparator::from()].into(),
        )
        .await
        .unwrap()
        .take_ids()
        .pop()
        .unwrap();

    // Fetch an e-mail message.
    let email = client
        .email_get(
            &email_id,
            [Property::Subject, Property::Preview, Property::Keywords].into(),
        )
        .await
        .unwrap()
        .unwrap();
    assert_eq!(email.preview().unwrap(), "test");
    assert_eq!(email.subject().unwrap(), "test");
    assert_eq!(email.keywords(), ["$draft"]);

    // Fetch only the updated properties of all mailboxes that changed
    // since a state.
    let mut request = client.build();
    let changes_request = request.changes_mailbox("n").max_changes(0);
    let properties_ref = changes_request.updated_properties_reference();
    let updated_ref = changes_request.updated_reference();
    request
        .get_mailbox()
        .ids_ref(updated_ref)
        .properties_ref(properties_ref);
    for mailbox in request
        .send()
        .await
        .unwrap()
        .unwrap_method_responses()
        .pop()
        .unwrap()
        .unwrap_get_mailbox()
        .unwrap()
        .take_list()
    {
        println!("Changed mailbox: {:#?}", mailbox);
    }

    // Delete the mailbox including any messages
    client.mailbox_destroy(&mailbox_id, true).await.unwrap();

    // Open an EventSource connection with the JMAP server.
    let mut stream = client
        .event_source(
            [
                TypeState::Email,
                TypeState::EmailDelivery,
                TypeState::Mailbox,
                TypeState::EmailSubmission,
                TypeState::Identity,
            ]
            .into(),
            false,
            60.into(),
            None,
        )
        .await
        .unwrap();

    // Consume events received over EventSource.
    while let Some(event) = stream.next().await {
        let changes = event.unwrap();
        println!("-> Change id: {:?}", changes.id());
        for account_id in changes.changed_accounts() {
            println!(" Account {} has changes:", account_id);
            if let Some(account_changes) = changes.changes(account_id) {
                for (type_state, state_id) in account_changes {
                    println!("   Type {:?} has a new state {}.", type_state, state_id);
                }
            }
        }
    }

More examples available under the examples directory.

Testing

To run the testsuite:

 $ cargo test --all-features

Conformed RFCs

License

Licensed under either of

  • Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
  • MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.

Copyright (C) 2022, Stalwart Labs Ltd.

Modules

Structs

Enums

Type Aliases