@@ -153,6 +153,29 @@ impl Service {
153153
154154 format ! ( "{base_url}/{API_VERSION_URL_PREFIX}/user/email/verify/{token}" )
155155 }
156+
157+ /// Send reset password email.
158+ ///
159+ /// # Errors
160+ ///
161+ /// This function will return an error if unable to send an email.
162+ ///
163+ /// # Panics
164+ ///
165+ /// This function will panic if the multipart builder had an error.
166+ pub async fn send_reset_password_mail ( & self , to : & str , username : & str , password : & str ) -> Result < ( ) , ServiceError > {
167+ let builder = self . get_builder ( to) . await ;
168+
169+ let mail = build_letter ( & password, username, builder) ?;
170+
171+ match self . mailer . send ( mail) . await {
172+ Ok ( _res) => Ok ( ( ) ) ,
173+ Err ( e) => {
174+ eprintln ! ( "Failed to send email: {e}" ) ;
175+ Err ( ServiceError :: FailedToSendVerificationEmail )
176+ }
177+ }
178+ }
156179}
157180
158181fn build_letter ( verification_url : & str , username : & str , builder : MessageBuilder ) -> Result < Message , ServiceError > {
@@ -197,6 +220,50 @@ fn build_content(verification_url: &str, username: &str) -> Result<(String, Stri
197220 Ok ( ( plain_body, html_body) )
198221}
199222
223+ fn build_reset_password_letter ( password : & str , username : & str , builder : MessageBuilder ) -> Result < Message , ServiceError > {
224+ let ( plain_body, html_body) = build_reset_password_content ( password, username) . map_err ( |e| {
225+ tracing:: error!( "{e}" ) ;
226+ ServiceError :: InternalServerError
227+ } ) ?;
228+
229+ Ok ( builder
230+ . subject ( "Torrust - Password reset" )
231+ . multipart (
232+ MultiPart :: alternative ( )
233+ . singlepart (
234+ SinglePart :: builder ( )
235+ . header ( lettre:: message:: header:: ContentType :: TEXT_PLAIN )
236+ . body ( plain_body) ,
237+ )
238+ . singlepart (
239+ SinglePart :: builder ( )
240+ . header ( lettre:: message:: header:: ContentType :: TEXT_HTML )
241+ . body ( html_body) ,
242+ ) ,
243+ )
244+ . expect ( "the `multipart` builder had an error" ) )
245+ }
246+
247+ fn build_reset_password_content ( password : & str , username : & str ) -> Result < ( String , String ) , tera:: Error > {
248+ let plain_body = format ! (
249+ "
250+ Hello, {username}!
251+
252+ Your password has been reset.
253+
254+ Find below your new password:
255+ {password}
256+
257+ We recommend replacing it as soon as possible with a new and strong password of your own.
258+ "
259+ ) ;
260+ let mut context = Context :: new ( ) ;
261+ context. insert ( "password" , & password) ;
262+ context. insert ( "username" , & username) ;
263+ let html_body = TEMPLATES . render ( "html_reset_password" , & context) ?;
264+ Ok ( ( plain_body, html_body) )
265+ }
266+
200267pub type Mailer = AsyncSmtpTransport < Tokio1Executor > ;
201268
202269#[ cfg( test) ]
0 commit comments