@@ -3,10 +3,12 @@ use std::sync::Mutex;
33
44use crate :: util:: errors:: { server_error, AppResult } ;
55
6+ use crate :: middleware:: log_request:: add_custom_metadata;
67use lettre:: transport:: file:: FileTransport ;
78use lettre:: transport:: smtp:: authentication:: { Credentials , Mechanism } ;
89use lettre:: transport:: smtp:: SmtpTransport ;
910use lettre:: { Message , Transport } ;
11+ use rand:: distributions:: { Alphanumeric , DistString } ;
1012
1113#[ derive( Debug ) ]
1214pub struct Emails {
@@ -94,7 +96,21 @@ or go to https://{domain}/me/pending-invites to manage all of your crate ownersh
9496 }
9597
9698 fn send ( & self , recipient : & str , subject : & str , body : & str ) -> AppResult < ( ) > {
99+ // The message ID is normally generated by the SMTP server, but if we let it generate the
100+ // ID there will be no way for the crates.io application to know the ID of the message it
101+ // just sent, as it's not included in the SMTP response.
102+ //
103+ // Our support staff needs to know the message ID to be able to find misdelivered emails.
104+ // Because of that we're generating a random message ID, hoping the SMTP server doesn't
105+ // replace it when it relays the message.
106+ let message_id = format ! (
107+ "<{}@{}>" ,
108+ Alphanumeric . sample_string( & mut rand:: thread_rng( ) , 32 ) ,
109+ crate :: config:: domain_name( ) ,
110+ ) ;
111+
97112 let email = Message :: builder ( )
113+ . message_id ( Some ( message_id. clone ( ) ) )
98114 . to ( recipient. parse ( ) ?)
99115 . from ( self . sender_address ( ) . parse ( ) ?)
100116 . subject ( subject)
@@ -106,23 +122,42 @@ or go to https://{domain}/me/pending-invites to manage all of your crate ownersh
106122 login,
107123 password,
108124 } => {
109- SmtpTransport :: relay ( server) ?
110- . credentials ( Credentials :: new ( login. clone ( ) , password. clone ( ) ) )
111- . authentication ( vec ! [ Mechanism :: Plain ] )
112- . build ( )
113- . send ( & email)
114- . map_err ( |_| server_error ( "Error in sending email" ) ) ?;
125+ add_custom_metadata ( "email_backend" , "smtp" ) ;
126+
127+ SmtpTransport :: relay ( server)
128+ . and_then ( |transport| {
129+ transport
130+ . credentials ( Credentials :: new ( login. clone ( ) , password. clone ( ) ) )
131+ . authentication ( vec ! [ Mechanism :: Plain ] )
132+ . build ( )
133+ . send ( & email)
134+ } )
135+ . map_err ( |e| {
136+ add_custom_metadata ( "email_error" , e) ;
137+ server_error ( "Failed to send the email" )
138+ } ) ?;
139+
140+ add_custom_metadata ( "email_id" , message_id) ;
115141 }
116142 EmailBackend :: FileSystem { path } => {
117- FileTransport :: new ( & path)
118- . send ( & email)
119- . map_err ( |_| server_error ( "Email file could not be generated" ) ) ?;
143+ add_custom_metadata ( "email_backend" , "fs" ) ;
144+
145+ let id = FileTransport :: new ( & path) . send ( & email) . map_err ( |err| {
146+ add_custom_metadata ( "email_error" , err) ;
147+ server_error ( "Email file could not be generated" )
148+ } ) ?;
149+
150+ add_custom_metadata ( "email_path" , path. join ( format ! ( "{id}.eml" ) ) . display ( ) ) ;
151+ }
152+ EmailBackend :: Memory { mails } => {
153+ add_custom_metadata ( "email_backend" , "memory" ) ;
154+
155+ mails. lock ( ) . unwrap ( ) . push ( StoredEmail {
156+ to : recipient. into ( ) ,
157+ subject : subject. into ( ) ,
158+ body : body. into ( ) ,
159+ } ) ;
120160 }
121- EmailBackend :: Memory { mails } => mails. lock ( ) . unwrap ( ) . push ( StoredEmail {
122- to : recipient. into ( ) ,
123- subject : subject. into ( ) ,
124- body : body. into ( ) ,
125- } ) ,
126161 }
127162
128163 Ok ( ( ) )
0 commit comments