sendgrid_rs/lib.rs
1//! This crate is a wrapper around SendGrid's v3 API using builder patterns to construct a payload
2//! to send. This crate does not have batteries included, does not perform any validations, and
3//! makes no assumptions other than what's specified in SendGrid's API documentation. To actually
4//! call the API, you must use some other mechnism for the HTTP connection (such as the reqwest
5//! crate).
6//!
7//! Everything stems from [Message](message/struct.Message.html) which you can construct using a
8//! [MessageBuilder](message/struct.MessageBuilder.html). When you're done with the
9//! `MessageBuilder` call `build()` to get the underlying `Message` and `to_json()` to get the
10//! entire `Message` output as a JSON string.
11//!
12//! # Examples
13//! ```
14//! # use sendgrid_rs::{MessageBuilder, ContactBuilder, PersonalizationBuilder, MailSettingsBuilder};
15//! let api_payload = MessageBuilder::new(
16//! ContactBuilder::new("from@example.com").name("from").build(),
17//! "Subject Line!",
18//! )
19//! .template_id("SENDGRID-TEMPLATE-ID")
20//! // Don't Actually send email. If you want to really send the email, delete the line below
21//! .mail_settings(MailSettingsBuilder::default().sandbox_mode().build())
22//! .personalization(
23//! PersonalizationBuilder::default()
24//! .to(ContactBuilder::new("to@example.com").name("to").build())
25//! .build(),
26//! )
27//! .build()
28//! .to_json();
29//! ```
30
31use serde::Serialize;
32
33pub mod attachment;
34pub mod mail_settings;
35pub mod message;
36pub mod personalization;
37pub mod tracking_settings;
38
39pub use crate::attachment::AttachmentBuilder;
40pub use crate::mail_settings::MailSettingsBuilder;
41pub use crate::message::MessageBuilder;
42pub use crate::personalization::PersonalizationBuilder;
43pub use crate::tracking_settings::{GaTrackingSettingBuilder, TrackingSettingsBuilder};
44
45/// Type used for SendGrid's asm fields for managing subscriptions
46/// Use `AsmBuilder` to construct this when adding it to a `Message`
47#[derive(Debug, Serialize)]
48pub struct Asm {
49 group_id: i32,
50 groups_to_display: Vec<i32>,
51}
52
53/// A builder pattern for constructing `Asm`
54/// Make sure you call `build()` to consume the builder and retrieve the underyling `Asm`
55pub struct AsmBuilder {
56 asm: Asm,
57}
58
59impl AsmBuilder {
60 /// Creates the builder. `group_id` is the only required paramteter which is associated
61 /// to the SendGrid group_id for `Asm` subscriptions
62 ///
63 /// # Examples
64 /// ```
65 /// # use sendgrid_rs::AsmBuilder;
66 ///
67 /// let builder = AsmBuilder::new(1);
68 /// ```
69 pub fn new(group_id: i32) -> Self {
70 AsmBuilder {
71 asm: Asm {
72 group_id,
73 groups_to_display: vec![],
74 },
75 }
76 }
77
78 /// Adds a display group to the `Asm`
79 ///
80 /// # Examples
81 /// ```
82 /// # use sendgrid_rs::AsmBuilder;
83 ///
84 /// let builder = AsmBuilder::new(1)
85 /// .group_to_display(2)
86 /// .group_to_display(3);
87 /// ```
88 pub fn group_to_display(mut self, group: i32) -> Self {
89 self.asm.groups_to_display.push(group);
90 self
91 }
92
93 /// Consumes the `AsmBuilder` and returns the underlying `Asm`
94 ///
95 /// # Examples
96 /// ```
97 /// # use sendgrid_rs::AsmBuilder;
98 ///
99 /// let asm = AsmBuilder::new(1).build();
100 /// ```
101 pub fn build(self) -> Asm {
102 self.asm
103 }
104}
105
106/// `Content` is the struct used to add content fields on SendGrid's API
107/// This is essentially a key/value store that serializes into the correct format
108#[derive(Debug, Serialize)]
109pub struct Content {
110 #[serde(rename = "type")]
111 c_type: String,
112 value: String,
113}
114
115impl Content {
116 /// Constructs a `Content`, this requires a content type (mime type) and value
117 ///
118 /// # Examples
119 /// ```
120 /// # use sendgrid_rs::Content;
121 ///
122 /// let content = Content::new("text/plain", "Message Content");
123 /// ```
124 pub fn new<S: Into<String>>(c_type: S, value: S) -> Self {
125 Content {
126 c_type: c_type.into(),
127 value: value.into(),
128 }
129 }
130}
131
132/// Struct that holds the data needed for the 'contact' section in the SendGrid API.
133/// Use a `ContactBuilder` to construct this.
134#[derive(Serialize, Debug)]
135pub struct Contact {
136 email: String,
137 name: Option<String>,
138}
139
140impl Contact {
141 fn new(email: impl Into<String>, name: Option<String>) -> Contact {
142 Contact {
143 email: email.into(),
144 name,
145 }
146 }
147}
148
149/// Builder pattern for `Contact`. Make sure you call `build()` when you're done to consume the
150/// builder and return the underlying `Contact`.
151pub struct ContactBuilder {
152 contact: Contact,
153}
154
155impl ContactBuilder {
156 /// Construct a new `ContactBuilder`. Email address is the only required parameter
157 ///
158 /// # Examples
159 /// ```
160 /// # use sendgrid_rs::ContactBuilder;
161 ///
162 /// let builder = ContactBuilder::new("from@example.com");
163 /// ```
164 pub fn new(email: impl Into<String>) -> Self {
165 ContactBuilder {
166 contact: Contact::new(email, None),
167 }
168 }
169
170 /// Set the name of the `Contact`
171 ///
172 /// # Examples
173 /// ```
174 /// # use sendgrid_rs::ContactBuilder;
175 ///
176 /// let builder = ContactBuilder::new("from@example.com")
177 /// .name("From");
178 /// ```
179 pub fn name(mut self, name: impl Into<String>) -> Self {
180 self.contact.name = Some(name.into());
181 self
182 }
183
184 /// Consume the builder and return the underlying `Contact`
185 ///
186 /// # Examples
187 /// ```
188 /// # use sendgrid_rs::ContactBuilder;
189 ///
190 /// let builder = ContactBuilder::new("from@example.com").build();
191 /// ```
192 pub fn build(self) -> Contact {
193 self.contact
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use crate::{ContactBuilder, MessageBuilder};
200
201 #[test]
202 fn it_works() {
203 let m = MessageBuilder::new(
204 ContactBuilder::new("from@from.com").name("from").build(),
205 "subject",
206 )
207 .build();
208 println!("{}", m.to_json());
209 }
210}