Skip to main content

email_transport_restate/
lib.rs

1//! Restate ingress transport for outbound email delivery.
2//!
3//! This crate implements [`email_transport::Transport`] on top of a Restate
4//! `Email.send` ingress invocation, so the same application code can hand a
5//! message to a durable queue instead of a provider. The wire contract it
6//! submits is owned by [`restate-email`](https://docs.rs/restate-email); the
7//! worker side of the contract lives there as well. Depending on this crate
8//! never pulls in the Restate SDK.
9//!
10//! [`RestateTransport`] follows a send as far as its [`InvocationMode`] says:
11//! in the default [`InvocationMode::Queued`] mode it returns once Restate has
12//! durably accepted the invocation and reports the invocation id; in
13//! [`InvocationMode::Sent`] mode it waits for the worker and returns the
14//! worker's provider report. A per-send [`RestateSendOptions`] overrides the
15//! configured mode and may delay a queued invocation.
16//!
17//! # Quick start
18//!
19//! ```rust,no_run
20//! use email_message::{Address, Body, Message};
21//! use email_transport::{SendOptions, Transport};
22//! use email_transport_restate::{RestateTransport, TransportKey};
23//!
24//! # async fn send() -> Result<(), Box<dyn std::error::Error>> {
25//! let message = Message::builder(Body::text("Welcome"))
26//!     .from_mailbox("sender@example.com".parse()?)
27//!     .to(vec![Address::Mailbox("recipient@example.com".parse()?)])
28//!     .build_outbound()?;
29//!
30//! let transport = RestateTransport::new(
31//!     TransportKey::new("transactional")?,
32//!     "http://127.0.0.1:8080".parse()?,
33//! );
34//! transport.send(&message, &SendOptions::default()).await?;
35//! # Ok(())
36//! # }
37//! ```
38//!
39//! # Authentication
40//!
41//! Restate Cloud ingress requires an API key as a bearer token; configure it
42//! with [`RestateTransportBuilder::bearer_token`]. Self-hosted Restate has no
43//! built-in ingress authentication; a fronting reverse proxy that expects
44//! the same `Authorization: Bearer` header is covered by the same setter,
45//! and any other header scheme can be attached to a custom
46//! [`reqwest::Client`] passed to [`RestateTransportBuilder::client`].
47//!
48//! # Features
49//!
50//! The default feature set enables the default `reqwest` client stack.
51//! Disable default features to choose `reqwest`'s transport/TLS features
52//! explicitly.
53//!
54//! - `schemars`: forwards JSON Schema derivation to the re-exported
55//!   `restate-email` queue payload types.
56//!
57//! # Example programs
58//!
59//! - [`invoke_local_worker`](https://github.com/sagikazarmark/email-rs/blob/main/crates/email-transport-restate/examples/invoke_local_worker.rs)
60//!   invokes `Email.send` through Restate ingress with a raw HTTP client and
61//!   waits for the response.
62//! - [`direct_or_restate`](https://github.com/sagikazarmark/email-rs/blob/main/crates/email-transport-restate/examples/direct_or_restate.rs)
63//!   sends through the same application function using either a direct
64//!   provider transport or [`RestateTransport`].
65
66mod transport;
67
68pub use restate_email::{
69    InvocationMode, RestateSendOptions, SendRequest, SendRequestSeed, SendResponse, TransportKey,
70};
71pub use transport::{RestateTransport, RestateTransportBuilder};