rust_gmail/lib.rs
1#![forbid(unsafe_code)]
2#![deny(missing_docs)]
3#![deny(missing_debug_implementations)]
4
5//! # A Rust library to interact with the google Gmail API using a service account.
6//!
7//! Currently focused only on support for sending emails but this may change in the future.
8//! Available both as async (default) or as blocking using the "blocking" feature.
9//!
10//! Note that usage of this lib will require a google API service account with domain wide delegation for gmail setup with a google cloud project with the gmail API enabled.
11//! Links for more information:
12//! - <https://cloud.google.com/iam/docs/service-account-overview>
13//! - <https://support.google.com/a/answer/162106?hl=en&fl=1&sjid=12697421685211806668-NA>
14//! - <https://developers.google.com/gmail/api/guides>
15//!
16//! ## Features
17//! There is currently only one feature, `blocking` which will add blocking alternatives to all async functions with the same name suffixed with `_blocking`.
18//! E.g. `send_email_blocking` instead of `send_email`.
19//!
20//! ## Examples
21//! Examples of how to use this crate.
22//!
23//! ### Async Example
24//! ```rust
25//! let email_client = GmailClient::builder(
26//! "service_account.json",
27//! "noreply@example.test",
28//! )?
29//! .build()
30//! .await?;
31//!
32//! email_client
33//! .send_email("some_user@domain.test")
34//! .await?;
35//! ```
36//!
37//! ### Blocking Example
38//! Note: Requires the `blocking` feature.
39//! ```rust
40//! let email_client = GmailClient::builder(
41//! "service_account.json",
42//! "noreply@example.test",
43//! )?
44//! .build_blocking()?;
45//!
46//! email_client
47//! .send_email_blocking("some_user@domain.test")?;
48//! ```
49
50use std::path::Path;
51
52use async_impl::{send_email::send_email, token::retrieve_token};
53use error::Result;
54use service_account::ServiceAccount;
55
56/// Types for error handling.
57pub mod error;
58
59mod async_impl;
60mod common;
61mod service_account;
62
63#[cfg(feature = "blocking")]
64mod blocking;
65
66/// The `GmailClientBuilder` is the intended way of creating a [`GmailClient`].
67#[derive(Debug, Clone)]
68pub struct GmailClientBuilder {
69 service_account: ServiceAccount,
70 send_from_email: String,
71 mock_mode: bool,
72}
73
74impl<'a> GmailClientBuilder {
75 /// Create a new `GmailClientBuilder`.
76 /// Will return an error if unable to read & parse the `service_account_path` if, for example, the file does not exist or has an incorrect format.
77 pub fn new<P: AsRef<Path>, S: Into<String>>(
78 service_account_path: P,
79 send_from_email: S,
80 ) -> Result<Self> {
81 Ok(Self {
82 service_account: ServiceAccount::load_from_file(service_account_path)?,
83 send_from_email: send_from_email.into(),
84 mock_mode: false,
85 })
86 }
87
88 /// Set "mock mode" which, if set to true, will log print the email instead of sending it.
89 pub fn mock_mode(mut self, enabled: bool) -> Self {
90 self.mock_mode = enabled;
91 self
92 }
93
94 /// Build a [`GmailClient`] from this `GmailClientBuilder`.
95 /// Note: This function will retrieve an access token from the Google API and as such make an API request.
96 pub async fn build(self) -> Result<GmailClient> {
97 let token = retrieve_token(&self.service_account, &self.send_from_email).await?;
98
99 Ok(GmailClient {
100 send_from_email: self.send_from_email,
101 token,
102 mock_mode: self.mock_mode,
103 })
104 }
105
106 /// A blocking alternative to the [`build()`] function.
107 #[cfg(feature = "blocking")]
108 pub fn build_blocking(self) -> Result<GmailClient> {
109 use blocking::token::retrieve_token_blocking;
110
111 let token = retrieve_token_blocking(&self.service_account, &self.send_from_email)?;
112
113 Ok(GmailClient {
114 send_from_email: self.send_from_email,
115 token,
116 mock_mode: self.mock_mode,
117 })
118 }
119}
120
121/// A client ready to send emails through the Gmail API.
122#[derive(Debug, Clone)]
123pub struct GmailClient {
124 send_from_email: String,
125 token: String,
126 mock_mode: bool,
127}
128
129impl GmailClient {
130 /// Alias for [`GmailClientBuilder::new()`].
131 pub fn builder<P: AsRef<Path>, S: Into<String>>(
132 service_account_path: P,
133 send_from_email: S,
134 ) -> Result<GmailClientBuilder> {
135 GmailClientBuilder::new(service_account_path, send_from_email)
136 }
137
138 /// Send an email to `send_to_email` with the specified `subject` and `content`.
139 pub async fn send_email(
140 &self,
141 send_to_email: &str,
142 subject: &str,
143 content: &str,
144 ) -> Result<()> {
145 send_email(
146 send_to_email,
147 subject,
148 content,
149 &self.token,
150 &self.send_from_email,
151 self.mock_mode,
152 )
153 .await
154 }
155
156 /// A blocking alternative to [`send_email()`].
157 #[cfg(feature = "blocking")]
158 pub fn send_email_blocking(
159 &self,
160 send_to_email: &str,
161 subject: &str,
162 content: &str,
163 ) -> Result<()> {
164 use blocking::send_email::send_email_blocking;
165
166 send_email_blocking(
167 send_to_email,
168 subject,
169 content,
170 &self.token,
171 &self.send_from_email,
172 self.mock_mode,
173 )
174 }
175}