1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3pub use client::Resend;
53pub(crate) use config::Config;
54
55mod api_keys;
56mod audiences;
57mod batch;
58mod broadcasts;
59mod client;
60mod config;
61mod contacts;
62mod domains;
63mod emails;
64mod error;
65pub mod events;
66pub mod rate_limit;
67
68pub mod services {
69 pub use super::api_keys::ApiKeysSvc;
72 pub use super::audiences::AudiencesSvc;
73 pub use super::batch::BatchSvc;
74 pub use super::broadcasts::BroadcastsSvc;
75 pub use super::contacts::ContactsSvc;
76 pub use super::domains::DomainsSvc;
77 pub use super::emails::EmailsSvc;
78}
79
80pub mod types {
81 pub use super::api_keys::types::{
84 ApiKey, ApiKeyId, ApiKeyToken, CreateApiKeyOptions, Permission,
85 };
86 pub use super::audiences::types::{Audience, AudienceId, CreateAudienceResponse};
87 pub use super::batch::types::SendEmailBatchResponse;
88 pub use super::broadcasts::types::{
89 Broadcast, BroadcastId, CreateBroadcastOptions, CreateBroadcastResponse,
90 RemoveBroadcastResponse, SendBroadcastOptions, SendBroadcastResponse,
91 UpdateBroadcastOptions, UpdateBroadcastResponse,
92 };
93 pub use super::contacts::types::{Contact, ContactChanges, ContactData, ContactId};
94 pub use super::domains::types::{
95 CreateDomainOptions, DkimRecordType, Domain, DomainChanges, DomainDkimRecord, DomainId,
96 DomainRecord, DomainSpfRecord, DomainStatus, ProxyStatus, Region, SpfRecordType, Tls,
97 UpdateDomainResponse,
98 };
99 pub use super::emails::types::{
100 Attachment, CancelScheduleResponse, ContentOrPath, CreateEmailBaseOptions,
101 CreateEmailResponse, Email, EmailId, Tag, UpdateEmailOptions, UpdateEmailResponse,
102 };
103 pub use super::error::types::{ErrorKind, ErrorResponse};
104}
105
106#[derive(Debug, thiserror::Error)]
110pub enum Error {
111 #[error("http error: {0}")]
113 Http(#[from] reqwest::Error),
114
115 #[error("resend error: {0}")]
117 Resend(#[from] types::ErrorResponse),
118
119 #[error("Failed to parse Resend API response. Received: \n{0}")]
121 Parse(String),
122
123 #[error("Too many requests. Limit is {ratelimit_limit:?} per {ratelimit_reset:?} seconds.")]
126 RateLimit {
127 ratelimit_limit: Option<u64>,
128 ratelimit_remaining: Option<u64>,
129 ratelimit_reset: Option<u64>,
130 },
131}
132
133#[cfg(test)]
134mod test {
135 use crate::Error;
136
137 #[allow(dead_code, clippy::redundant_pub_crate)]
138 pub(crate) struct LocatedError<E: std::error::Error + 'static> {
139 inner: E,
140 location: &'static std::panic::Location<'static>,
141 }
142
143 impl From<Error> for LocatedError<Error> {
144 #[track_caller]
145 fn from(value: Error) -> Self {
146 Self {
147 inner: value,
148 location: std::panic::Location::caller(),
149 }
150 }
151 }
152
153 impl<T: std::error::Error + 'static> std::fmt::Debug for LocatedError<T> {
154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 write!(
156 f,
157 "{}:{}:{}\n{:?}",
158 self.location.file(),
159 self.location.line(),
160 self.location.column(),
161 self.inner
162 )
163 }
164 }
165
166 #[allow(clippy::redundant_pub_crate)]
167 pub(crate) type DebugResult<T, E = LocatedError<Error>> = Result<T, E>;
168}
169
170pub type Result<T, E = Error> = std::result::Result<T, E>;
174
175#[cfg(test)]
176pub(crate) mod tests {
177 use std::sync::LazyLock;
178
179 use crate::Resend;
180
181 #[allow(clippy::redundant_pub_crate)]
182 pub(crate) static CLIENT: LazyLock<Resend> = LazyLock::new(Resend::default);
189}