swadhinbiswas

[email protected]
2026-07-25 12:46:07 +0600 committed NaN years ago
8a89bce
commit 8a89bce
1 file changed
+113 -0
Showing 1 changed file+113-0
▼crates/justapi-core/src/mail/types.rs
+113-0
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