sendgrid_api/
lib.rs

1//! A fully generated, opinionated API client library for SendGrid.
2//!
3//! [![docs.rs](https://docs.rs/sendgrid-api/badge.svg)](https://docs.rs/sendgrid-api)
4//!
5//! ## API Details
6//!
7//! The Beta endpoints for the new Email Activity APIs - functionality is subject to change without notice. You may not have access to this Beta endpoint.
8//!
9//! Email Activity offers filtering and search by event type for two days worth of data. There is an optional add-on to store 60 days worth of data. This add-on also gives you access to the ability to download a CSV of the 60 days worth of email event data. The Beta endpoints for the new Email Activity APIs - functionality is subject to change without notice. You may not have access to this Beta endpoint.
10//!
11//! Email Activity offers filtering and search by event type for two days worth of data. There is an optional add-on to store 60 days worth of data. This add-on also gives you access to the ability to download a CSV of the 60 days worth of email event data.
12//!
13//!
14//!
15//!
16//!
17//!
18//! ## Client Details
19//!
20//! This client is generated from the [SendGrid OpenAPI
21//! specs](https://raw.githubusercontent.com/sendgrid/sendgrid-oai/main/oai.json) based on API spec version ``. This way it will remain
22//! up to date as features are added. The documentation for the crate is generated
23//! along with the code to make this library easy to use.
24//!
25//!
26//! To install the library, add the following to your `Cargo.toml` file.
27//!
28//! ```toml
29//! [dependencies]
30//! sendgrid-api = "0.7.0"
31//! ```
32//!
33//! ## Basic example
34//!
35//! Typical use will require intializing a `Client`. This requires
36//! a user agent string and set of credentials.
37//!
38//! ```rust
39//! use sendgrid_api::Client;
40//!
41//! let sendgrid = Client::new(
42//!     String::from("api-key"),
43//! );
44//! ```
45//!
46//! Alternatively, the library can search for most of the variables required for
47//! the client in the environment:
48//!
49//! - `SENDGRID_API_KEY`
50//!
51//! And then you can create a client from the environment.
52//!
53//! ```rust
54//! use sendgrid_api::Client;
55//!
56//! let sendgrid = Client::new_from_env();
57//! ```
58//!
59#![allow(clippy::derive_partial_eq_without_eq)]
60#![allow(clippy::too_many_arguments)]
61#![allow(clippy::nonstandard_macro_braces)]
62#![allow(clippy::large_enum_variant)]
63#![allow(clippy::tabs_in_doc_comments)]
64#![allow(missing_docs)]
65#![cfg_attr(docsrs, feature(doc_cfg))]
66
67pub mod alerts;
68pub mod api_key_permissions;
69pub mod api_keys;
70pub mod blocks_api;
71pub mod bounces_api;
72pub mod campaigns_api;
73pub mod cancel_scheduled_sends;
74pub mod categories;
75pub mod certificates;
76pub mod contacts;
77pub mod contacts_api_custom_fields;
78pub mod contacts_api_lists;
79pub mod contacts_api_recipients;
80pub mod contacts_api_segments;
81pub mod csv_ui_only;
82pub mod custom_fields;
83pub mod designs_api;
84pub mod domain_authentication;
85pub mod email_address_validation;
86pub mod email_cname_records;
87pub mod invalid_emails_api;
88pub mod ip_access_management;
89pub mod ip_addresses;
90pub mod ip_pools;
91pub mod ip_warmup;
92pub mod link_branding;
93pub mod lists;
94pub mod mail_send;
95pub mod marketing_campaigns_stats;
96pub mod query;
97pub mod reverse_dns;
98pub mod segmenting_contacts;
99pub mod segmenting_contacts_beta;
100pub mod send_test_email;
101pub mod sender_identities_api;
102pub mod sender_verification;
103pub mod senders;
104pub mod settings_enforced_tls;
105pub mod settings_inbound_parse;
106pub mod settings_mail;
107pub mod settings_partner;
108pub mod settings_tracking;
109pub mod single_sends;
110pub mod single_sign_on_settings;
111pub mod single_sign_on_teammates;
112pub mod spam_reports_api;
113pub mod stats;
114pub mod subuser_monitor_settings;
115pub mod subuser_statistics;
116pub mod subusers_api;
117pub mod suppressions;
118pub mod suppressions_global;
119pub mod suppressions_unsubscribe_groups;
120pub mod teammates;
121pub mod traits;
122pub mod transactional_templates;
123pub mod transactional_templates_versions;
124pub mod types;
125pub mod users_api;
126#[doc(hidden)]
127pub mod utils;
128pub mod webhooks;
129
130pub use reqwest::{header::HeaderMap, StatusCode};
131
132#[derive(Debug)]
133pub struct Response<T> {
134    pub status: reqwest::StatusCode,
135    pub headers: reqwest::header::HeaderMap,
136    pub body: T,
137}
138
139impl<T> Response<T> {
140    pub fn new(status: reqwest::StatusCode, headers: reqwest::header::HeaderMap, body: T) -> Self {
141        Self {
142            status,
143            headers,
144            body,
145        }
146    }
147}
148
149type ClientResult<T> = Result<T, ClientError>;
150
151use thiserror::Error;
152
153/// Errors returned by the client
154#[derive(Debug, Error)]
155pub enum ClientError {
156    /// utf8 convertion error
157    #[error(transparent)]
158    FromUtf8Error(#[from] std::string::FromUtf8Error),
159    /// URL Parsing Error
160    #[error(transparent)]
161    UrlParserError(#[from] url::ParseError),
162    /// Serde JSON parsing error
163    #[error(transparent)]
164    SerdeJsonError(#[from] serde_json::Error),
165    /// Errors returned by reqwest
166    #[error(transparent)]
167    ReqwestError(#[from] reqwest::Error),
168    /// Errors returned by reqwest::header
169    #[error(transparent)]
170    InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
171    /// Errors returned by reqwest middleware
172    #[error(transparent)]
173    ReqwestMiddleWareError(#[from] reqwest_middleware::Error),
174    /// Generic HTTP Error
175    #[error("HTTP Error. Code: {status}, message: {error}")]
176    HttpError {
177        status: http::StatusCode,
178        headers: reqwest::header::HeaderMap,
179        error: String,
180    },
181}
182
183pub const FALLBACK_HOST: &str = "https://api.sendgrid.com/v3";
184
185mod progenitor_support {
186    use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
187
188    const PATH_SET: &AsciiSet = &CONTROLS
189        .add(b' ')
190        .add(b'"')
191        .add(b'#')
192        .add(b'<')
193        .add(b'>')
194        .add(b'?')
195        .add(b'`')
196        .add(b'{')
197        .add(b'}');
198
199    #[allow(dead_code)]
200    pub(crate) fn encode_path(pc: &str) -> String {
201        utf8_percent_encode(pc, PATH_SET).to_string()
202    }
203}
204
205#[derive(Debug, Default)]
206pub(crate) struct Message {
207    pub body: Option<reqwest::Body>,
208    pub content_type: Option<String>,
209}
210
211use std::env;
212
213#[derive(Debug, Default, Clone)]
214pub struct RootDefaultServer {}
215
216impl RootDefaultServer {
217    pub fn default_url(&self) -> &str {
218        "https://api.sendgrid.com/v3"
219    }
220}
221
222/// Entrypoint for interacting with the API client.
223#[derive(Clone)]
224pub struct Client {
225    host: String,
226    host_override: Option<String>,
227    token: String,
228
229    client: reqwest_middleware::ClientWithMiddleware,
230}
231
232impl Client {
233    /// Create a new Client struct.
234    ///
235    /// # Panics
236    ///
237    /// This function will panic if the internal http client fails to create
238    pub fn new<T>(token: T) -> Self
239    where
240        T: ToString,
241    {
242        let client = reqwest::Client::builder()
243            .redirect(reqwest::redirect::Policy::none())
244            .build();
245        let retry_policy =
246            reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
247        match client {
248            Ok(c) => {
249                let client = reqwest_middleware::ClientBuilder::new(c)
250                    // Trace HTTP requests. See the tracing crate to make use of these traces.
251                    .with(reqwest_tracing::TracingMiddleware::default())
252                    // Retry failed requests.
253                    .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
254                        reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
255                        |req: &reqwest::Request| req.try_clone().is_some(),
256                    ))
257                    .build();
258
259                let host = RootDefaultServer::default().default_url().to_string();
260
261                Client {
262                    host,
263                    host_override: None,
264                    token: token.to_string(),
265
266                    client,
267                }
268            }
269            Err(e) => panic!("creating reqwest client failed: {:?}", e),
270        }
271    }
272
273    /// Override the host for all endpoins in the client.
274    pub fn with_host_override<H>(&mut self, host: H) -> &mut Self
275    where
276        H: ToString,
277    {
278        self.host_override = Some(host.to_string());
279        self
280    }
281
282    /// Disables the global host override for the client.
283    pub fn remove_host_override(&mut self) -> &mut Self {
284        self.host_override = None;
285        self
286    }
287
288    pub fn get_host_override(&self) -> Option<&str> {
289        self.host_override.as_deref()
290    }
291
292    pub(crate) fn url(&self, path: &str, host: Option<&str>) -> String {
293        format!(
294            "{}{}",
295            self.get_host_override()
296                .or(host)
297                .unwrap_or(self.host.as_str()),
298            path
299        )
300    }
301
302    /// Create a new Client struct from environment variables.
303    ///
304    /// The following environment variables are expected to be set:
305    ///   * `SENDGRID_API_KEY`
306    ///
307    /// # Panics
308    ///
309    /// This function will panic if the expected environment variables can not be found
310    pub fn new_from_env() -> Self {
311        let token = env::var("SENDGRID_API_KEY").expect("must set SENDGRID_API_KEY");
312
313        Client::new(token)
314    }
315
316    async fn url_and_auth(&self, uri: &str) -> ClientResult<(reqwest::Url, Option<String>)> {
317        let parsed_url = uri.parse::<reqwest::Url>()?;
318        let auth = format!("Bearer {}", self.token);
319        Ok((parsed_url, Some(auth)))
320    }
321
322    async fn request_raw(
323        &self,
324        method: reqwest::Method,
325        uri: &str,
326        message: Message,
327    ) -> ClientResult<reqwest::Response> {
328        let (url, auth) = self.url_and_auth(uri).await?;
329        let instance = <&Client>::clone(&self);
330        let mut req = instance.client.request(method.clone(), url);
331        // Set the default headers.
332        req = req.header(
333            reqwest::header::ACCEPT,
334            reqwest::header::HeaderValue::from_static("application/json"),
335        );
336
337        if let Some(content_type) = &message.content_type {
338            req = req.header(
339                reqwest::header::CONTENT_TYPE,
340                reqwest::header::HeaderValue::from_str(content_type).unwrap(),
341            );
342        } else {
343            req = req.header(
344                reqwest::header::CONTENT_TYPE,
345                reqwest::header::HeaderValue::from_static("application/json"),
346            );
347        }
348
349        if let Some(auth_str) = auth {
350            req = req.header(http::header::AUTHORIZATION, &*auth_str);
351        }
352        if let Some(body) = message.body {
353            req = req.body(body);
354        }
355        Ok(req.send().await?)
356    }
357
358    async fn request<Out>(
359        &self,
360        method: reqwest::Method,
361        uri: &str,
362        message: Message,
363    ) -> ClientResult<crate::Response<Out>>
364    where
365        Out: serde::de::DeserializeOwned + 'static + Send,
366    {
367        let response = self.request_raw(method, uri, message).await?;
368
369        let status = response.status();
370        let headers = response.headers().clone();
371
372        let response_body = response.bytes().await?;
373
374        if status.is_success() {
375            log::debug!("Received successful response. Read payload.");
376            let parsed_response = if status == http::StatusCode::NO_CONTENT
377                || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
378            {
379                serde_json::from_str("null")?
380            } else {
381                serde_json::from_slice::<Out>(&response_body)?
382            };
383            Ok(crate::Response::new(status, headers, parsed_response))
384        } else {
385            let error = if response_body.is_empty() {
386                ClientError::HttpError {
387                    status,
388                    headers,
389                    error: "empty response".into(),
390                }
391            } else {
392                ClientError::HttpError {
393                    status,
394                    headers,
395                    error: String::from_utf8_lossy(&response_body).into(),
396                }
397            };
398
399            Err(error)
400        }
401    }
402
403    async fn request_with_links<Out>(
404        &self,
405        method: http::Method,
406        uri: &str,
407        message: Message,
408    ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Out>)>
409    where
410        Out: serde::de::DeserializeOwned + 'static + Send,
411    {
412        let response = self.request_raw(method, uri, message).await?;
413
414        let status = response.status();
415        let headers = response.headers().clone();
416        let link = response
417            .headers()
418            .get(http::header::LINK)
419            .and_then(|l| l.to_str().ok())
420            .and_then(|l| parse_link_header::parse(l).ok())
421            .as_ref()
422            .and_then(crate::utils::next_link);
423
424        let response_body = response.bytes().await?;
425
426        if status.is_success() {
427            log::debug!("Received successful response. Read payload.");
428
429            let parsed_response = if status == http::StatusCode::NO_CONTENT
430                || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
431            {
432                serde_json::from_str("null")?
433            } else {
434                serde_json::from_slice::<Out>(&response_body)?
435            };
436            Ok((link, crate::Response::new(status, headers, parsed_response)))
437        } else {
438            let error = if response_body.is_empty() {
439                ClientError::HttpError {
440                    status,
441                    headers,
442                    error: "empty response".into(),
443                }
444            } else {
445                ClientError::HttpError {
446                    status,
447                    headers,
448                    error: String::from_utf8_lossy(&response_body).into(),
449                }
450            };
451            Err(error)
452        }
453    }
454
455    /* TODO: make this more DRY */
456    #[allow(dead_code)]
457    async fn post_form<Out>(
458        &self,
459        uri: &str,
460        form: reqwest::multipart::Form,
461    ) -> ClientResult<crate::Response<Out>>
462    where
463        Out: serde::de::DeserializeOwned + 'static + Send,
464    {
465        let (url, auth) = self.url_and_auth(uri).await?;
466
467        let instance = <&Client>::clone(&self);
468
469        let mut req = instance.client.request(http::Method::POST, url);
470
471        // Set the default headers.
472        req = req.header(
473            reqwest::header::ACCEPT,
474            reqwest::header::HeaderValue::from_static("application/json"),
475        );
476
477        if let Some(auth_str) = auth {
478            req = req.header(http::header::AUTHORIZATION, &*auth_str);
479        }
480
481        req = req.multipart(form);
482
483        let response = req.send().await?;
484
485        let status = response.status();
486        let headers = response.headers().clone();
487
488        let response_body = response.bytes().await?;
489
490        if status.is_success() {
491            log::debug!("Received successful response. Read payload.");
492            let parsed_response = if status == http::StatusCode::NO_CONTENT
493                || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
494            {
495                serde_json::from_str("null")?
496            } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
497                // Parse the output as a string.
498                let s = String::from_utf8(response_body.to_vec())?;
499                serde_json::from_value(serde_json::json!(&s))?
500            } else {
501                serde_json::from_slice::<Out>(&response_body)?
502            };
503            Ok(crate::Response::new(status, headers, parsed_response))
504        } else {
505            let error = if response_body.is_empty() {
506                ClientError::HttpError {
507                    status,
508                    headers,
509                    error: "empty response".into(),
510                }
511            } else {
512                ClientError::HttpError {
513                    status,
514                    headers,
515                    error: String::from_utf8_lossy(&response_body).into(),
516                }
517            };
518
519            Err(error)
520        }
521    }
522
523    /* TODO: make this more DRY */
524    #[allow(dead_code)]
525    async fn request_with_accept_mime<Out>(
526        &self,
527        method: reqwest::Method,
528        uri: &str,
529        accept_mime_type: &str,
530    ) -> ClientResult<crate::Response<Out>>
531    where
532        Out: serde::de::DeserializeOwned + 'static + Send,
533    {
534        let (url, auth) = self.url_and_auth(uri).await?;
535
536        let instance = <&Client>::clone(&self);
537
538        let mut req = instance.client.request(method, url);
539
540        // Set the default headers.
541        req = req.header(
542            reqwest::header::ACCEPT,
543            reqwest::header::HeaderValue::from_str(accept_mime_type)?,
544        );
545
546        if let Some(auth_str) = auth {
547            req = req.header(http::header::AUTHORIZATION, &*auth_str);
548        }
549
550        let response = req.send().await?;
551
552        let status = response.status();
553        let headers = response.headers().clone();
554
555        let response_body = response.bytes().await?;
556
557        if status.is_success() {
558            log::debug!("Received successful response. Read payload.");
559            let parsed_response = if status == http::StatusCode::NO_CONTENT
560                || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
561            {
562                serde_json::from_str("null")?
563            } else if std::any::TypeId::of::<Out>() == std::any::TypeId::of::<String>() {
564                // Parse the output as a string.
565                let s = String::from_utf8(response_body.to_vec())?;
566                serde_json::from_value(serde_json::json!(&s))?
567            } else {
568                serde_json::from_slice::<Out>(&response_body)?
569            };
570            Ok(crate::Response::new(status, headers, parsed_response))
571        } else {
572            let error = if response_body.is_empty() {
573                ClientError::HttpError {
574                    status,
575                    headers,
576                    error: "empty response".into(),
577                }
578            } else {
579                ClientError::HttpError {
580                    status,
581                    headers,
582                    error: String::from_utf8_lossy(&response_body).into(),
583                }
584            };
585
586            Err(error)
587        }
588    }
589
590    /* TODO: make this more DRY */
591    #[allow(dead_code)]
592    async fn request_with_mime<Out>(
593        &self,
594        method: reqwest::Method,
595        uri: &str,
596        content: &[u8],
597        mime_type: &str,
598    ) -> ClientResult<crate::Response<Out>>
599    where
600        Out: serde::de::DeserializeOwned + 'static + Send,
601    {
602        let (url, auth) = self.url_and_auth(uri).await?;
603
604        let instance = <&Client>::clone(&self);
605
606        let mut req = instance.client.request(method, url);
607
608        // Set the default headers.
609        req = req.header(
610            reqwest::header::ACCEPT,
611            reqwest::header::HeaderValue::from_static("application/json"),
612        );
613        req = req.header(
614            reqwest::header::CONTENT_TYPE,
615            reqwest::header::HeaderValue::from_bytes(mime_type.as_bytes()).unwrap(),
616        );
617        // We are likely uploading a file so add the right headers.
618        req = req.header(
619            reqwest::header::HeaderName::from_static("x-upload-content-type"),
620            reqwest::header::HeaderValue::from_static("application/octet-stream"),
621        );
622        req = req.header(
623            reqwest::header::HeaderName::from_static("x-upload-content-length"),
624            reqwest::header::HeaderValue::from_bytes(format!("{}", content.len()).as_bytes())
625                .unwrap(),
626        );
627
628        if let Some(auth_str) = auth {
629            req = req.header(http::header::AUTHORIZATION, &*auth_str);
630        }
631
632        if content.len() > 1 {
633            let b = bytes::Bytes::copy_from_slice(content);
634            // We are uploading a file so add that as the body.
635            req = req.body(b);
636        }
637
638        let response = req.send().await?;
639
640        let status = response.status();
641        let headers = response.headers().clone();
642
643        let response_body = response.bytes().await?;
644
645        if status.is_success() {
646            log::debug!("Received successful response. Read payload.");
647            let parsed_response = if status == http::StatusCode::NO_CONTENT
648                || std::any::TypeId::of::<Out>() == std::any::TypeId::of::<()>()
649            {
650                serde_json::from_str("null")?
651            } else {
652                serde_json::from_slice::<Out>(&response_body)?
653            };
654            Ok(crate::Response::new(status, headers, parsed_response))
655        } else {
656            let error = if response_body.is_empty() {
657                ClientError::HttpError {
658                    status,
659                    headers,
660                    error: "empty response".into(),
661                }
662            } else {
663                ClientError::HttpError {
664                    status,
665                    headers,
666                    error: String::from_utf8_lossy(&response_body).into(),
667                }
668            };
669
670            Err(error)
671        }
672    }
673
674    async fn request_entity<D>(
675        &self,
676        method: http::Method,
677        uri: &str,
678        message: Message,
679    ) -> ClientResult<crate::Response<D>>
680    where
681        D: serde::de::DeserializeOwned + 'static + Send,
682    {
683        let r = self.request(method, uri, message).await?;
684        Ok(r)
685    }
686
687    #[allow(dead_code)]
688    async fn get<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
689    where
690        D: serde::de::DeserializeOwned + 'static + Send,
691    {
692        self.request_entity(http::Method::GET, uri, message).await
693    }
694
695    #[allow(dead_code)]
696    async fn get_all_pages<D>(&self, uri: &str, _message: Message) -> ClientResult<Response<Vec<D>>>
697    where
698        D: serde::de::DeserializeOwned + 'static + Send,
699    {
700        // TODO: implement this.
701        self.unfold(uri).await
702    }
703
704    /// "unfold" paginated results of a vector of items
705    #[allow(dead_code)]
706    async fn unfold<D>(&self, uri: &str) -> ClientResult<crate::Response<Vec<D>>>
707    where
708        D: serde::de::DeserializeOwned + 'static + Send,
709    {
710        let mut global_items = Vec::new();
711        let (new_link, mut response) = self.get_pages(uri).await?;
712        let mut link = new_link;
713        while !response.body.is_empty() {
714            global_items.append(&mut response.body);
715            // We need to get the next link.
716            if let Some(url) = &link {
717                let url = reqwest::Url::parse(&url.0)?;
718                let (new_link, new_response) = self.get_pages_url(&url).await?;
719                link = new_link;
720                response = new_response;
721            }
722        }
723
724        Ok(Response::new(
725            response.status,
726            response.headers,
727            global_items,
728        ))
729    }
730
731    #[allow(dead_code)]
732    async fn get_pages<D>(
733        &self,
734        uri: &str,
735    ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
736    where
737        D: serde::de::DeserializeOwned + 'static + Send,
738    {
739        self.request_with_links(http::Method::GET, uri, Message::default())
740            .await
741    }
742
743    #[allow(dead_code)]
744    async fn get_pages_url<D>(
745        &self,
746        url: &reqwest::Url,
747    ) -> ClientResult<(Option<crate::utils::NextLink>, crate::Response<Vec<D>>)>
748    where
749        D: serde::de::DeserializeOwned + 'static + Send,
750    {
751        self.request_with_links(http::Method::GET, url.as_str(), Message::default())
752            .await
753    }
754
755    #[allow(dead_code)]
756    async fn post<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
757    where
758        D: serde::de::DeserializeOwned + 'static + Send,
759    {
760        self.request_entity(http::Method::POST, uri, message).await
761    }
762
763    #[allow(dead_code)]
764    async fn patch<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
765    where
766        D: serde::de::DeserializeOwned + 'static + Send,
767    {
768        self.request_entity(http::Method::PATCH, uri, message).await
769    }
770
771    #[allow(dead_code)]
772    async fn put<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
773    where
774        D: serde::de::DeserializeOwned + 'static + Send,
775    {
776        self.request_entity(http::Method::PUT, uri, message).await
777    }
778
779    #[allow(dead_code)]
780    async fn delete<D>(&self, uri: &str, message: Message) -> ClientResult<crate::Response<D>>
781    where
782        D: serde::de::DeserializeOwned + 'static + Send,
783    {
784        self.request_entity(http::Method::DELETE, uri, message)
785            .await
786    }
787
788    pub fn alerts(&self) -> alerts::Alerts {
789        alerts::Alerts::new(self.clone())
790    }
791
792    pub fn api_key_permissions(&self) -> api_key_permissions::ApiKeyPermissions {
793        api_key_permissions::ApiKeyPermissions::new(self.clone())
794    }
795
796    pub fn api_keys(&self) -> api_keys::ApiKeys {
797        api_keys::ApiKeys::new(self.clone())
798    }
799
800    pub fn blocks_api(&self) -> blocks_api::BlocksApi {
801        blocks_api::BlocksApi::new(self.clone())
802    }
803
804    pub fn bounces_api(&self) -> bounces_api::BouncesApi {
805        bounces_api::BouncesApi::new(self.clone())
806    }
807
808    pub fn campaigns_api(&self) -> campaigns_api::CampaignsApi {
809        campaigns_api::CampaignsApi::new(self.clone())
810    }
811
812    pub fn cancel_scheduled_sends(&self) -> cancel_scheduled_sends::CancelScheduledSends {
813        cancel_scheduled_sends::CancelScheduledSends::new(self.clone())
814    }
815
816    pub fn categories(&self) -> categories::Categories {
817        categories::Categories::new(self.clone())
818    }
819
820    pub fn certificates(&self) -> certificates::Certificates {
821        certificates::Certificates::new(self.clone())
822    }
823
824    pub fn contacts(&self) -> contacts::Contacts {
825        contacts::Contacts::new(self.clone())
826    }
827
828    pub fn contacts_api_custom_fields(
829        &self,
830    ) -> contacts_api_custom_fields::ContactsApiCustomFields {
831        contacts_api_custom_fields::ContactsApiCustomFields::new(self.clone())
832    }
833
834    pub fn contacts_api_lists(&self) -> contacts_api_lists::ContactsApiLists {
835        contacts_api_lists::ContactsApiLists::new(self.clone())
836    }
837
838    pub fn contacts_api_recipients(&self) -> contacts_api_recipients::ContactsApiRecipients {
839        contacts_api_recipients::ContactsApiRecipients::new(self.clone())
840    }
841
842    pub fn contacts_api_segments(&self) -> contacts_api_segments::ContactsApiSegments {
843        contacts_api_segments::ContactsApiSegments::new(self.clone())
844    }
845
846    pub fn csv_ui_only(&self) -> csv_ui_only::CsvUiOnly {
847        csv_ui_only::CsvUiOnly::new(self.clone())
848    }
849
850    pub fn custom_fields(&self) -> custom_fields::CustomFields {
851        custom_fields::CustomFields::new(self.clone())
852    }
853
854    pub fn designs_api(&self) -> designs_api::DesignsApi {
855        designs_api::DesignsApi::new(self.clone())
856    }
857
858    pub fn domain_authentication(&self) -> domain_authentication::DomainAuthentication {
859        domain_authentication::DomainAuthentication::new(self.clone())
860    }
861
862    pub fn email_address_validation(&self) -> email_address_validation::EmailAddressValidation {
863        email_address_validation::EmailAddressValidation::new(self.clone())
864    }
865
866    pub fn email_cname_records(&self) -> email_cname_records::EmailCnameRecords {
867        email_cname_records::EmailCnameRecords::new(self.clone())
868    }
869
870    pub fn invalid_emails_api(&self) -> invalid_emails_api::InvalidEmailsApi {
871        invalid_emails_api::InvalidEmailsApi::new(self.clone())
872    }
873
874    pub fn ip_access_management(&self) -> ip_access_management::IpAccessManagement {
875        ip_access_management::IpAccessManagement::new(self.clone())
876    }
877
878    pub fn ip_addresses(&self) -> ip_addresses::IpAddresses {
879        ip_addresses::IpAddresses::new(self.clone())
880    }
881
882    pub fn ip_pools(&self) -> ip_pools::IpPools {
883        ip_pools::IpPools::new(self.clone())
884    }
885
886    pub fn ip_warmup(&self) -> ip_warmup::IpWarmup {
887        ip_warmup::IpWarmup::new(self.clone())
888    }
889
890    pub fn link_branding(&self) -> link_branding::LinkBranding {
891        link_branding::LinkBranding::new(self.clone())
892    }
893
894    pub fn lists(&self) -> lists::Lists {
895        lists::Lists::new(self.clone())
896    }
897
898    pub fn mail_send(&self) -> mail_send::MailSend {
899        mail_send::MailSend::new(self.clone())
900    }
901
902    pub fn marketing_campaigns_stats(&self) -> marketing_campaigns_stats::MarketingCampaignsStats {
903        marketing_campaigns_stats::MarketingCampaignsStats::new(self.clone())
904    }
905
906    pub fn query(&self) -> query::Query {
907        query::Query::new(self.clone())
908    }
909
910    pub fn reverse_dns(&self) -> reverse_dns::ReverseDns {
911        reverse_dns::ReverseDns::new(self.clone())
912    }
913
914    pub fn segmenting_contacts(&self) -> segmenting_contacts::SegmentingContacts {
915        segmenting_contacts::SegmentingContacts::new(self.clone())
916    }
917
918    pub fn segmenting_contacts_beta(&self) -> segmenting_contacts_beta::SegmentingContactsBeta {
919        segmenting_contacts_beta::SegmentingContactsBeta::new(self.clone())
920    }
921
922    pub fn send_test_email(&self) -> send_test_email::SendTestEmail {
923        send_test_email::SendTestEmail::new(self.clone())
924    }
925
926    pub fn sender_identities_api(&self) -> sender_identities_api::SenderIdentitiesApi {
927        sender_identities_api::SenderIdentitiesApi::new(self.clone())
928    }
929
930    pub fn sender_verification(&self) -> sender_verification::SenderVerification {
931        sender_verification::SenderVerification::new(self.clone())
932    }
933
934    pub fn senders(&self) -> senders::Senders {
935        senders::Senders::new(self.clone())
936    }
937
938    pub fn settings_enforced_tls(&self) -> settings_enforced_tls::SettingsEnforcedTls {
939        settings_enforced_tls::SettingsEnforcedTls::new(self.clone())
940    }
941
942    pub fn settings_inbound_parse(&self) -> settings_inbound_parse::SettingsInboundParse {
943        settings_inbound_parse::SettingsInboundParse::new(self.clone())
944    }
945
946    pub fn settings_mail(&self) -> settings_mail::SettingsMail {
947        settings_mail::SettingsMail::new(self.clone())
948    }
949
950    pub fn settings_partner(&self) -> settings_partner::SettingsPartner {
951        settings_partner::SettingsPartner::new(self.clone())
952    }
953
954    pub fn settings_tracking(&self) -> settings_tracking::SettingsTracking {
955        settings_tracking::SettingsTracking::new(self.clone())
956    }
957
958    pub fn single_sends(&self) -> single_sends::SingleSends {
959        single_sends::SingleSends::new(self.clone())
960    }
961
962    pub fn single_sign_on_settings(&self) -> single_sign_on_settings::SingleSignOnSettings {
963        single_sign_on_settings::SingleSignOnSettings::new(self.clone())
964    }
965
966    pub fn single_sign_on_teammates(&self) -> single_sign_on_teammates::SingleSignOnTeammates {
967        single_sign_on_teammates::SingleSignOnTeammates::new(self.clone())
968    }
969
970    pub fn spam_reports_api(&self) -> spam_reports_api::SpamReportsApi {
971        spam_reports_api::SpamReportsApi::new(self.clone())
972    }
973
974    pub fn stats(&self) -> stats::Stats {
975        stats::Stats::new(self.clone())
976    }
977
978    pub fn subuser_monitor_settings(&self) -> subuser_monitor_settings::SubuserMonitorSettings {
979        subuser_monitor_settings::SubuserMonitorSettings::new(self.clone())
980    }
981
982    pub fn subuser_statistics(&self) -> subuser_statistics::SubuserStatistics {
983        subuser_statistics::SubuserStatistics::new(self.clone())
984    }
985
986    pub fn subusers_api(&self) -> subusers_api::SubusersApi {
987        subusers_api::SubusersApi::new(self.clone())
988    }
989
990    pub fn suppressions(&self) -> suppressions::Suppressions {
991        suppressions::Suppressions::new(self.clone())
992    }
993
994    pub fn suppressions_global(&self) -> suppressions_global::SuppressionsGlobal {
995        suppressions_global::SuppressionsGlobal::new(self.clone())
996    }
997
998    pub fn suppressions_unsubscribe_groups(
999        &self,
1000    ) -> suppressions_unsubscribe_groups::SuppressionsUnsubscribeGroups {
1001        suppressions_unsubscribe_groups::SuppressionsUnsubscribeGroups::new(self.clone())
1002    }
1003
1004    pub fn teammates(&self) -> teammates::Teammates {
1005        teammates::Teammates::new(self.clone())
1006    }
1007
1008    pub fn transactional_templates(&self) -> transactional_templates::TransactionalTemplates {
1009        transactional_templates::TransactionalTemplates::new(self.clone())
1010    }
1011
1012    pub fn transactional_templates_versions(
1013        &self,
1014    ) -> transactional_templates_versions::TransactionalTemplatesVersions {
1015        transactional_templates_versions::TransactionalTemplatesVersions::new(self.clone())
1016    }
1017
1018    pub fn users_api(&self) -> users_api::UsersApi {
1019        users_api::UsersApi::new(self.clone())
1020    }
1021
1022    pub fn webhooks(&self) -> webhooks::Webhooks {
1023        webhooks::Webhooks::new(self.clone())
1024    }
1025}