@@ -24,11 +24,21 @@ use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
24
24
25
25
use crate :: SmtpClient ;
26
26
27
+ #[ cfg( feature = "dkim" ) ]
28
+ #[ derive( Debug , Default , PartialEq ) ]
29
+ enum Dkim {
30
+ #[ default]
31
+ Unsigned ,
32
+ Signed ,
33
+ }
34
+
27
35
#[ derive( Debug , Default ) ]
28
36
pub struct Message < ' x > {
29
37
pub mail_from : Address < ' x > ,
30
38
pub rcpt_to : Vec < Address < ' x > > ,
31
39
pub body : Cow < ' x , [ u8 ] > ,
40
+ #[ cfg( feature = "dkim" ) ]
41
+ dkim : Dkim ,
32
42
}
33
43
34
44
#[ derive( Debug , Default ) ]
@@ -49,10 +59,10 @@ pub struct Parameter<'x> {
49
59
}
50
60
51
61
impl < T : AsyncRead + AsyncWrite + Unpin > SmtpClient < T > {
52
- /// Sends a message to the server.
53
- pub async fn send < ' x > ( & mut self , message : impl IntoMessage < ' x > ) -> crate :: Result < ( ) > {
62
+ /// Send headers
63
+ #[ inline]
64
+ async fn send_headers < ' x > ( & mut self , message : & Message < ' x > ) -> crate :: Result < ( ) > {
54
65
// Send mail-from
55
- let message = message. into_message ( ) ?;
56
66
self . mail_from (
57
67
message. mail_from . email . as_ref ( ) ,
58
68
& message. mail_from . parameters ,
@@ -64,42 +74,38 @@ impl<T: AsyncRead + AsyncWrite + Unpin> SmtpClient<T> {
64
74
self . rcpt_to ( rcpt. email . as_ref ( ) , & rcpt. parameters ) . await ?;
65
75
}
66
76
77
+ Ok ( ( ) )
78
+ }
79
+
80
+ /// Convert into message and send that message to the server.
81
+ pub async fn send < ' x > ( & mut self , message : impl IntoMessage < ' x > ) -> crate :: Result < ( ) > {
82
+ // Send mail-from
83
+ let message = message. into_message ( ) ?;
84
+
85
+ self . send_msg ( & message) . await
86
+ }
87
+
88
+ /// Send a message to the server.
89
+ #[ inline]
90
+ pub async fn send_msg < ' x > ( & mut self , message : & Message < ' x > ) -> crate :: Result < ( ) > {
91
+ self . send_headers ( message) . await ?;
92
+
67
93
// Send message
68
94
self . data ( message. body . as_ref ( ) ) . await
69
95
}
70
96
71
- /// Sends a message to the server.
97
+ /// Convert into message, sign and send that message to the server.
72
98
#[ cfg( feature = "dkim" ) ]
73
99
pub async fn send_signed < ' x , V : mail_auth:: common:: crypto:: SigningKey > (
74
100
& mut self ,
75
101
message : impl IntoMessage < ' x > ,
76
102
signer : & mail_auth:: dkim:: DkimSigner < V , mail_auth:: dkim:: Done > ,
77
103
) -> crate :: Result < ( ) > {
78
- // Send mail-from
79
-
80
- use mail_auth:: common:: headers:: HeaderWriter ;
81
- let message = message. into_message ( ) ?;
82
- self . mail_from (
83
- message. mail_from . email . as_ref ( ) ,
84
- & message. mail_from . parameters ,
85
- )
86
- . await ?;
87
-
88
- // Send rcpt-to
89
- for rcpt in & message. rcpt_to {
90
- self . rcpt_to ( rcpt. email . as_ref ( ) , & rcpt. parameters ) . await ?;
91
- }
92
-
93
- // Sign message
94
- let signature = signer
95
- . sign ( message. body . as_ref ( ) )
96
- . map_err ( |_| crate :: Error :: MissingCredentials ) ?;
97
- let mut signed_message = Vec :: with_capacity ( message. body . len ( ) + 64 ) ;
98
- signature. write_header ( & mut signed_message) ;
99
- signed_message. extend_from_slice ( message. body . as_ref ( ) ) ;
104
+ let mut message = message. into_message ( ) ?;
105
+ message. sign ( signer) ?;
100
106
101
107
// Send message
102
- self . data ( & signed_message ) . await
108
+ self . send_msg ( & message ) . await
103
109
}
104
110
105
111
pub async fn write_message ( & mut self , message : & [ u8 ] ) -> tokio:: io:: Result < ( ) > {
@@ -145,6 +151,8 @@ impl<'x> Message<'x> {
145
151
mail_from : from. into ( ) ,
146
152
rcpt_to : to. into_iter ( ) . map ( Into :: into) . collect ( ) ,
147
153
body : body. into ( ) ,
154
+ #[ cfg( feature = "dkim" ) ]
155
+ dkim : Dkim :: Unsigned ,
148
156
}
149
157
}
150
158
@@ -154,26 +162,56 @@ impl<'x> Message<'x> {
154
162
mail_from : Address :: default ( ) ,
155
163
rcpt_to : Vec :: new ( ) ,
156
164
body : Default :: default ( ) ,
165
+ #[ cfg( feature = "dkim" ) ]
166
+ dkim : Dkim :: Unsigned ,
157
167
}
158
168
}
159
169
160
170
/// Set the sender of the message.
171
+ #[ inline]
161
172
pub fn from ( mut self , address : impl Into < Address < ' x > > ) -> Self {
162
173
self . mail_from = address. into ( ) ;
163
174
self
164
175
}
165
176
166
177
/// Add a message recipient.
178
+ #[ inline]
167
179
pub fn to ( mut self , address : impl Into < Address < ' x > > ) -> Self {
168
180
self . rcpt_to . push ( address. into ( ) ) ;
169
181
self
170
182
}
171
183
172
184
/// Set the message body.
185
+ #[ inline]
173
186
pub fn body ( mut self , body : impl Into < Cow < ' x , [ u8 ] > > ) -> Self {
174
187
self . body = body. into ( ) ;
175
188
self
176
189
}
190
+
191
+ /// Sign a message
192
+ #[ cfg( feature = "dkim" ) ]
193
+ #[ inline]
194
+ pub fn sign < V : mail_auth:: common:: crypto:: SigningKey > (
195
+ & mut self ,
196
+ signer : & mail_auth:: dkim:: DkimSigner < V , mail_auth:: dkim:: Done > ,
197
+ ) -> crate :: Result < ( ) > {
198
+ use mail_auth:: common:: headers:: HeaderWriter ;
199
+
200
+ let signature = signer
201
+ . sign ( self . body . as_ref ( ) )
202
+ . map_err ( |_| crate :: Error :: MissingCredentials ) ?;
203
+ let mut signed_message = Vec :: with_capacity ( self . body . len ( ) + 64 ) ;
204
+ signature. write_header ( & mut signed_message) ;
205
+ signed_message. extend_from_slice ( self . body . as_ref ( ) ) ;
206
+
207
+ if self . dkim == Dkim :: Signed {
208
+ return Err ( crate :: Error :: MessageDkimSigned ) ;
209
+ }
210
+ self . body = signed_message. into ( ) ;
211
+ self . dkim = Dkim :: Signed ;
212
+
213
+ Ok ( ( ) )
214
+ }
177
215
}
178
216
179
217
impl < ' x > From < & ' x str > for Address < ' x > {
@@ -204,17 +242,20 @@ impl<'x> Address<'x> {
204
242
}
205
243
206
244
impl < ' x > Parameters < ' x > {
245
+ #[ inline]
207
246
pub fn new ( ) -> Self {
208
247
Self { params : Vec :: new ( ) }
209
248
}
210
249
250
+ #[ inline]
211
251
pub fn add ( & mut self , param : impl Into < Parameter < ' x > > ) -> & mut Self {
212
252
self . params . push ( param. into ( ) ) ;
213
253
self
214
254
}
215
255
}
216
256
217
257
impl < ' x > From < & ' x str > for Parameter < ' x > {
258
+ #[ inline]
218
259
fn from ( value : & ' x str ) -> Self {
219
260
Parameter {
220
261
key : value. into ( ) ,
@@ -224,6 +265,7 @@ impl<'x> From<&'x str> for Parameter<'x> {
224
265
}
225
266
226
267
impl < ' x > From < ( & ' x str , & ' x str ) > for Parameter < ' x > {
268
+ #[ inline]
227
269
fn from ( value : ( & ' x str , & ' x str ) ) -> Self {
228
270
Parameter {
229
271
key : value. 0 . into ( ) ,
@@ -233,6 +275,7 @@ impl<'x> From<(&'x str, &'x str)> for Parameter<'x> {
233
275
}
234
276
235
277
impl < ' x > From < ( String , String ) > for Parameter < ' x > {
278
+ #[ inline]
236
279
fn from ( value : ( String , String ) ) -> Self {
237
280
Parameter {
238
281
key : value. 0 . into ( ) ,
@@ -242,6 +285,7 @@ impl<'x> From<(String, String)> for Parameter<'x> {
242
285
}
243
286
244
287
impl < ' x > From < String > for Parameter < ' x > {
288
+ #[ inline]
245
289
fn from ( value : String ) -> Self {
246
290
Parameter {
247
291
key : value. into ( ) ,
@@ -272,11 +316,12 @@ impl<'x> Display for Parameter<'x> {
272
316
}
273
317
}
274
318
275
- pub trait IntoMessage < ' x > {
319
+ pub trait IntoMessage < ' x > : Sized {
276
320
fn into_message ( self ) -> crate :: Result < Message < ' x > > ;
277
321
}
278
322
279
323
impl < ' x > IntoMessage < ' x > for Message < ' x > {
324
+ #[ inline]
280
325
fn into_message ( self ) -> crate :: Result < Message < ' x > > {
281
326
Ok ( self )
282
327
}
@@ -347,6 +392,8 @@ impl<'x, 'y> IntoMessage<'x> for MessageBuilder<'y> {
347
392
} )
348
393
. collect ( ) ,
349
394
body : self . write_to_vec ( ) ?. into ( ) ,
395
+ #[ cfg( feature = "dkim" ) ]
396
+ dkim : Dkim :: Unsigned ,
350
397
} )
351
398
}
352
399
}
@@ -412,6 +459,7 @@ impl<'x> IntoMessage<'x> for mail_parser::Message<'x> {
412
459
} )
413
460
. collect ( ) ,
414
461
body : self . raw_message ,
462
+ dkim : Dkim :: Unsigned ,
415
463
} )
416
464
}
417
465
}
0 commit comments