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