8a89bce
commit 8a89bce
1 file changed
+113 -0
Showing 1 changed file+113-0
▼crates/justapi-core/src/mail/types.rs
+113-0
| @@ -0,0 +1,113 @@ | ||
1 | +/// Email address with optional display name. | |
2 | +#[derive(Debug, Clone)] | |
3 | +pub struct EmailAddress { | |
4 | + pub address: String, | |
5 | + pub name: Option<String>, | |
6 | +} | |
7 | + | |
8 | +impl EmailAddress { | |
9 | + pub fn new(address: impl Into<String>) -> Self { | |
10 | + Self { address: address.into(), name: None } | |
11 | + } | |
12 | + | |
13 | + pub fn named(address: impl Into<String>, name: impl Into<String>) -> Self { | |
14 | + Self { address: address.into(), name: Some(name.into()) } | |
15 | + } | |
16 | +} | |
17 | + | |
18 | +impl From<String> for EmailAddress { | |
19 | + fn from(s: String) -> Self { | |
20 | + Self::new(s) | |
21 | + } | |
22 | +} | |
23 | + | |
24 | +impl From<&str> for EmailAddress { | |
25 | + fn from(s: &str) -> Self { | |
26 | + Self::new(s.to_string()) | |
27 | + } | |
28 | +} | |
29 | + | |
30 | +/// A file attachment for an email. | |
31 | +#[derive(Debug, Clone)] | |
32 | +pub struct Attachment { | |
33 | + pub filename: String, | |
34 | + pub content_type: String, | |
35 | + pub data: Vec<u8>, | |
36 | + pub inline: bool, | |
37 | +} | |
38 | + | |
39 | +impl Attachment { | |
40 | + pub fn new(filename: impl Into<String>, data: Vec<u8>) -> Self { | |
41 | + let filename = filename.into(); | |
42 | + let content_type = mime_guess(&filename).unwrap_or("application/octet-stream"); | |
43 | + Self { filename, content_type: content_type.to_string(), data, inline: false } | |
44 | + } | |
45 | + | |
46 | + pub fn with_content_type( | |
47 | + filename: impl Into<String>, | |
48 | + content_type: impl Into<String>, | |
49 | + data: Vec<u8>, | |
50 | + ) -> Self { | |
51 | + Self { filename: filename.into(), content_type: content_type.into(), data, inline: false } | |
52 | + } | |
53 | + | |
54 | + pub fn inline(mut self) -> Self { | |
55 | + self.inline = true; | |
56 | + self | |
57 | + } | |
58 | +} | |
59 | + | |
60 | +fn mime_guess(filename: &str) -> Option<&'static str> { | |
61 | + let ext = filename.rsplit('.').next()?.to_lowercase(); | |
62 | + match ext.as_str() { | |
63 | + "txt" => Some("text/plain"), | |
64 | + "html" => Some("text/html"), | |
65 | + "json" => Some("application/json"), | |
66 | + "pdf" => Some("application/pdf"), | |
67 | + "png" => Some("image/png"), | |
68 | + "jpg" | "jpeg" => Some("image/jpeg"), | |
69 | + "gif" => Some("image/gif"), | |
70 | + "svg" => Some("image/svg+xml"), | |
71 | + "csv" => Some("text/csv"), | |
72 | + "zip" => Some("application/zip"), | |
73 | + "xml" => Some("application/xml"), | |
74 | + _ => None, | |
75 | + } | |
76 | +} | |
77 | + | |
78 | +/// SMTP connection configuration. | |
79 | +#[derive(Debug, Clone)] | |
80 | +pub struct SmtpConfig { | |
81 | + pub host: String, | |
82 | + pub port: u16, | |
83 | + pub username: Option<String>, | |
84 | + pub password: Option<String>, | |
85 | + pub use_tls: bool, | |
86 | + pub default_from: EmailAddress, | |
87 | + pub default_from_name: Option<String>, | |
88 | +} | |
89 | + | |
90 | +impl SmtpConfig { | |
91 | + pub fn new(host: impl Into<String>, port: u16, default_from: impl Into<String>) -> Self { | |
92 | + Self { | |
93 | + host: host.into(), | |
94 | + port, | |
95 | + username: None, | |
96 | + password: None, | |
97 | + use_tls: true, | |
98 | + default_from: EmailAddress::new(default_from), | |
99 | + default_from_name: None, | |
100 | + } | |
101 | + } | |
102 | + | |
103 | + pub fn credentials(mut self, username: impl Into<String>, password: impl Into<String>) -> Self { | |
104 | + self.username = Some(username.into()); | |
105 | + self.password = Some(password.into()); | |
106 | + self | |
107 | + } | |
108 | + | |
109 | + pub fn no_tls(mut self) -> Self { | |
110 | + self.use_tls = false; | |
111 | + self | |
112 | + } | |
113 | +} | |
0 | 114 | |