Gmail REST API client library, written in Rust.
https://developers.google.com/workspace/gmail/api/reference/rest
I/O Gmail can be consumed three ways, depending on how much of the I/O stack you want to own. Each mode is gated by cargo features.
Tip
I/O Gmail is written in Rust and uses cargo features to gate the client layers. The default feature set is declared in Cargo.toml or on docs.rs.
If you want a ready-to-use, standard, blocking client with TCP connection and TLS negociation managed for you:
[dependencies]
io-gmail = "0.0.1" # rustls-ring is enabled by defaultuse io_gmail::v1::client::GmailClientStd;
let mut client = GmailClientStd::connect("token", Default::default()).unwrap();
let out = client.profile_get().unwrap();
println!("Email address: {}", out.response.email_address);
let out = client.labels_list().unwrap();
for label in &out.response.labels {
println!("{}: {}", label.id, label.name);
}If you still want a standard, blocking client but you want to manage TCP and TLS on your own:
[dependencies]
io-gmail = { version = "0.0.1", default-features = false, features = ["client"] }
rustls = "0.23"
rustls-platform-verifier = "0.7"use std::{net::TcpStream, sync::Arc};
use io_gmail::v1::client::GmailClientStd;
use rustls::{ClientConfig, ClientConnection, StreamOwned};
use rustls_platform_verifier::ConfigVerifierExt;
// TLS config
let config = ClientConfig::with_platform_verifier().unwrap();
let server_name = "gmail.googleapis.com".try_into().unwrap();
let conn = ClientConnection::new(Arc::new(config), server_name).unwrap();
let tcp = TcpStream::connect(("gmail.googleapis.com", 443)).unwrap();
let stream = StreamOwned::new(conn, tcp);
// Standard, blocking client
let mut client = GmailClientStd::new(stream, "token", Default::default());
let out = client.profile_get().unwrap();
println!("Email address: {}", out.response.email_address);
let out = client.labels_list().unwrap();
for label in &out.response.labels {
println!("{}: {}", label.id, label.name);
}Otherwise you can build your own client using I/O-free coroutines directly:
[dependencies]
io-gmail = { version = "0.0.1", default-features = false }
rustls = "0.23"
rustls-platform-verifier = "0.7"
tokio = { version = "1", features = ["full"] }
tokio-rustls = "0.26"use std::sync::Arc;
use io_gmail::{coroutine::*, v1::rest::users::get_profile::GmailProfileGet};
use io_http::rfc6750::bearer::HttpAuthBearer;
use rustls::ClientConfig;
use rustls_platform_verifier::ConfigVerifierExt;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt},
net::TcpStream,
};
use tokio_rustls::TlsConnector;
#[tokio::main]
async fn main() {
// Async TLS connection
let config = ClientConfig::with_platform_verifier().unwrap();
let connector = TlsConnector::from(Arc::new(config));
let server_name = "gmail.googleapis.com".try_into().unwrap();
let tcp = TcpStream::connect(("gmail.googleapis.com", 443)).await.unwrap();
let mut stream = connector.connect(server_name, tcp).await.unwrap();
// Run the I/O-free coroutine against the async stream
let auth = HttpAuthBearer::new("token");
let mut coroutine = GmailProfileGet::new(&auth, "me").unwrap();
let mut arg: Option<&[u8]> = None;
let mut buf = [0u8; 8192];
let mut read_buf = Vec::<u8>::new();
let out = loop {
match coroutine.resume(arg.take()) {
GmailCoroutineState::Complete(Ok(out)) => break out,
GmailCoroutineState::Yielded(GmailYield::WantsRead) => {
let n = stream.read(&mut buf).await.unwrap();
read_buf.clear();
read_buf.extend_from_slice(&buf[..n]);
arg = Some(&read_buf);
}
GmailCoroutineState::Yielded(GmailYield::WantsWrite(bytes)) => {
stream.write_all(&bytes).await.unwrap();
}
GmailCoroutineState::Complete(Err(err)) => panic!("{err}"),
}
};
println!("Email address: {}", out.response.email_address);
}Important
For such advanced usage, it is preferable to read the architecture guide.
Have a look at real-world projects built on top of this library:
- io-email: Email client library
- Himalaya CLI: CLI to manage emails
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.8, 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 Gmail REST API reference, 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 spec references. The verification workflow catches most of this; it does not catch all of it. Bug reports are welcome and taken seriously.
- Last reviewed: 16/06/2026
This project is licensed under either of:
at your option.
- Chat on Matrix
- News on Mastodon or RSS
- Mail at pimalaya.org@posteo.net
Special thanks to the NLnet foundation and the European Commission that have been financially supporting the project for years:
- 2022 → 2023: NGI Assure
- 2023 → 2024: NGI Zero Entrust
- 2024 → 2026: NGI Zero Core
- 2027 in preparation…
If you appreciate the project, feel free to donate using one of the following providers:
