@@ -151,6 +151,29 @@ impl Service {
151
151
152
152
format ! ( "{base_url}/{API_VERSION_URL_PREFIX}/user/email/verify/{token}" )
153
153
}
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
+ }
154
177
}
155
178
156
179
fn 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
195
218
Ok ( ( plain_body, html_body) )
196
219
}
197
220
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
+
198
265
pub type Mailer = AsyncSmtpTransport < Tokio1Executor > ;
199
266
200
267
#[ cfg( test) ]
0 commit comments