Skip to main content

restate_email/
lib.rs

1//! Restate-backed worker contracts for outbound email delivery.
2//!
3//! This crate exposes the serializable email worker contract and an optional
4//! Restate service adapter. Provider-specific send options cross the queue
5//! boundary through the registry-driven [`SendRequestSeed`], using the
6//! provider-keyed wire representation owned by `email-transport`.
7//!
8//! The Restate service adapter is available as [`Service`] with the
9//! `service` feature. The caller-side ingress transport lives in the
10//! [`email-transport-restate`](https://docs.rs/email-transport-restate)
11//! crate, which submits this contract through Restate ingress without
12//! depending on `restate-sdk`.
13//!
14//! # Quick start
15//!
16//! ```rust
17//! # #[cfg(feature = "service")]
18//! # {
19//! use restate_email::{Service, StaticTransportRegistry};
20//! use restate_sdk::{endpoint::Endpoint, service::IntoServiceDefinition};
21//!
22//! let registry = StaticTransportRegistry::new();
23//! let service = Service::new(registry).into_service_definition();
24//! let _endpoint = Endpoint::builder().bind(service).build();
25//! # }
26//! ```
27//!
28//! # Securing the worker
29//!
30//! Restate signs every request it makes to an SDK endpoint when the runtime
31//! is configured with a request identity key. Verify those signatures by
32//! registering the corresponding public keys on the endpoint builder; once at
33//! least one key is registered, unsigned requests are rejected. Registering
34//! several keys keeps both the old and the new key valid during rotation:
35//!
36//! ```rust
37//! # #[cfg(feature = "service")]
38//! # fn build() -> Result<(), Box<dyn std::error::Error>> {
39//! # use restate_email::{Service, StaticTransportRegistry};
40//! # use restate_sdk::{endpoint::Endpoint, service::IntoServiceDefinition};
41//! # let service = Service::new(StaticTransportRegistry::new()).into_service_definition();
42//! let _endpoint = Endpoint::builder()
43//!     .bind(service)
44//!     .identity_key("publickeyv1_w7YHemBctH5Ck2nQRQ47iBBqhNHy4FV7t2Usbye2A6f")?
45//!     .identity_key("publickeyv1_ChjENKeMvCtRnqG2mrBK1HmPKufgFUc98K8B3ononQvp")?
46//!     .build();
47//! # Ok(())
48//! # }
49//! ```
50//!
51//! Identity keys authenticate the Restate runtime to the worker; callers
52//! authenticate to Restate ingress separately (see `email-transport-restate`).
53//!
54//! # Features
55//!
56//! The default feature set enables `service` for backwards-compatible worker
57//! builds. Disable default features to consume only the SDK-free wire contract.
58//!
59//! - `service`: Restate worker service adapter and transport registry.
60//! - `transport-resend`: registers Resend provider options and enables the
61//!   Resend worker example.
62//! - `schemars`: JSON Schema implementations and examples for queue contracts.
63//! - `rfc5322-string-compat`: accepts the legacy RFC 5322 string address shape
64//!   supported by `email-message`.
65//!
66//! # Platform support
67//!
68//! This crate targets native Restate workers. Transport implementations may
69//! support additional platforms, but [`Service`] depends on Restate's
70//! native endpoint/runtime integration.
71//!
72//! # Examples
73//!
74//! - [`restate_email_worker`](https://github.com/sagikazarmark/email-rs/blob/main/crates/restate-email/examples/restate_email_worker.rs)
75//!   builds a worker with a custom transport and optional identity-key
76//!   verification.
77//! - [`restate_resend_worker`](https://github.com/sagikazarmark/email-rs/blob/main/crates/restate-email/examples/restate_resend_worker.rs)
78//!   wires [`email_kit::transport::resend::ResendTransport`] into the service;
79//!   it requires the `transport-resend` feature.
80
81mod contract;
82mod options;
83#[cfg(feature = "service")]
84mod service;
85#[cfg(feature = "service")]
86pub mod transport;
87
88// `IdempotencyKey` and `CorrelationId` live in `email-transport` because they
89// flow through `SendOptions` directly.
90pub use contract::{SendRequest, SendRequestSeed, SendResponse, TransportKey};
91pub use email_transport::{
92    CorrelationId, IdempotencyKey, STRING_NEWTYPE_MAX_BYTES, SendOptions, StringNewtypeError,
93    TransportOption, TransportOptionRegistry, TransportOptionRegistryError, TransportOptions,
94    TransportOptionsSeed,
95};
96pub use options::{InvocationMode, RestateSendOptions};
97#[cfg(feature = "service")]
98pub use service::{Service, ServiceClient};
99#[cfg(feature = "service")]
100pub use transport::{
101    CatchAllTransportResolver, RuntimeBound, StaticTransportRegistry, TransportLookupError,
102    TransportResolver,
103};