|
|
@ -8,7 +8,7 @@ use lettre::{ |
|
|
|
transport::smtp::authentication::{Credentials, Mechanism as SmtpAuthMechanism}, |
|
|
|
transport::smtp::client::{Tls, TlsParameters}, |
|
|
|
transport::smtp::extension::ClientId, |
|
|
|
Address, SmtpTransport, Transport, |
|
|
|
Address, AsyncSmtpTransport, AsyncTransport, Tokio1Executor, |
|
|
|
}; |
|
|
|
|
|
|
|
use crate::{ |
|
|
@ -21,11 +21,11 @@ use crate::{ |
|
|
|
CONFIG, |
|
|
|
}; |
|
|
|
|
|
|
|
fn mailer() -> SmtpTransport { |
|
|
|
fn mailer() -> AsyncSmtpTransport<Tokio1Executor> { |
|
|
|
use std::time::Duration; |
|
|
|
let host = CONFIG.smtp_host().unwrap(); |
|
|
|
|
|
|
|
let smtp_client = SmtpTransport::builder_dangerous(host.as_str()) |
|
|
|
let smtp_client = AsyncSmtpTransport::<Tokio1Executor>::builder_dangerous(host.as_str()) |
|
|
|
.port(CONFIG.smtp_port()) |
|
|
|
.timeout(Some(Duration::from_secs(CONFIG.smtp_timeout()))); |
|
|
|
|
|
|
@ -110,7 +110,7 @@ fn get_template(template_name: &str, data: &serde_json::Value) -> Result<(String |
|
|
|
Ok((subject, body)) |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_password_hint(address: &str, hint: Option<String>) -> EmptyResult { |
|
|
|
pub async fn send_password_hint(address: &str, hint: Option<String>) -> EmptyResult { |
|
|
|
let template_name = if hint.is_some() { |
|
|
|
"email/pw_hint_some" |
|
|
|
} else { |
|
|
@ -119,10 +119,10 @@ pub fn send_password_hint(address: &str, hint: Option<String>) -> EmptyResult { |
|
|
|
|
|
|
|
let (subject, body_html, body_text) = get_text(template_name, json!({ "hint": hint, "url": CONFIG.domain() }))?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_delete_account(address: &str, uuid: &str) -> EmptyResult { |
|
|
|
pub async fn send_delete_account(address: &str, uuid: &str) -> EmptyResult { |
|
|
|
let claims = generate_delete_claims(uuid.to_string()); |
|
|
|
let delete_token = encode_jwt(&claims); |
|
|
|
|
|
|
@ -136,10 +136,10 @@ pub fn send_delete_account(address: &str, uuid: &str) -> EmptyResult { |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_verify_email(address: &str, uuid: &str) -> EmptyResult { |
|
|
|
pub async fn send_verify_email(address: &str, uuid: &str) -> EmptyResult { |
|
|
|
let claims = generate_verify_email_claims(uuid.to_string()); |
|
|
|
let verify_email_token = encode_jwt(&claims); |
|
|
|
|
|
|
@ -153,10 +153,10 @@ pub fn send_verify_email(address: &str, uuid: &str) -> EmptyResult { |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_welcome(address: &str) -> EmptyResult { |
|
|
|
pub async fn send_welcome(address: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/welcome", |
|
|
|
json!({ |
|
|
@ -164,10 +164,10 @@ pub fn send_welcome(address: &str) -> EmptyResult { |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_welcome_must_verify(address: &str, uuid: &str) -> EmptyResult { |
|
|
|
pub async fn send_welcome_must_verify(address: &str, uuid: &str) -> EmptyResult { |
|
|
|
let claims = generate_verify_email_claims(uuid.to_string()); |
|
|
|
let verify_email_token = encode_jwt(&claims); |
|
|
|
|
|
|
@ -180,10 +180,10 @@ pub fn send_welcome_must_verify(address: &str, uuid: &str) -> EmptyResult { |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_2fa_removed_from_org(address: &str, org_name: &str) -> EmptyResult { |
|
|
|
pub async fn send_2fa_removed_from_org(address: &str, org_name: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/send_2fa_removed_from_org", |
|
|
|
json!({ |
|
|
@ -192,10 +192,10 @@ pub fn send_2fa_removed_from_org(address: &str, org_name: &str) -> EmptyResult { |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_single_org_removed_from_org(address: &str, org_name: &str) -> EmptyResult { |
|
|
|
pub async fn send_single_org_removed_from_org(address: &str, org_name: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/send_single_org_removed_from_org", |
|
|
|
json!({ |
|
|
@ -204,10 +204,10 @@ pub fn send_single_org_removed_from_org(address: &str, org_name: &str) -> EmptyR |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_invite( |
|
|
|
pub async fn send_invite( |
|
|
|
address: &str, |
|
|
|
uuid: &str, |
|
|
|
org_id: Option<String>, |
|
|
@ -236,10 +236,10 @@ pub fn send_invite( |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_emergency_access_invite( |
|
|
|
pub async fn send_emergency_access_invite( |
|
|
|
address: &str, |
|
|
|
uuid: &str, |
|
|
|
emer_id: Option<String>, |
|
|
@ -267,10 +267,10 @@ pub fn send_emergency_access_invite( |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_emergency_access_invite_accepted(address: &str, grantee_email: &str) -> EmptyResult { |
|
|
|
pub async fn send_emergency_access_invite_accepted(address: &str, grantee_email: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/emergency_access_invite_accepted", |
|
|
|
json!({ |
|
|
@ -279,10 +279,10 @@ pub fn send_emergency_access_invite_accepted(address: &str, grantee_email: &str) |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_emergency_access_invite_confirmed(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
|
pub async fn send_emergency_access_invite_confirmed(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/emergency_access_invite_confirmed", |
|
|
|
json!({ |
|
|
@ -291,10 +291,10 @@ pub fn send_emergency_access_invite_confirmed(address: &str, grantor_name: &str) |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_emergency_access_recovery_approved(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
|
pub async fn send_emergency_access_recovery_approved(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/emergency_access_recovery_approved", |
|
|
|
json!({ |
|
|
@ -303,10 +303,10 @@ pub fn send_emergency_access_recovery_approved(address: &str, grantor_name: &str |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_emergency_access_recovery_initiated( |
|
|
|
pub async fn send_emergency_access_recovery_initiated( |
|
|
|
address: &str, |
|
|
|
grantee_name: &str, |
|
|
|
atype: &str, |
|
|
@ -322,10 +322,10 @@ pub fn send_emergency_access_recovery_initiated( |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_emergency_access_recovery_reminder( |
|
|
|
pub async fn send_emergency_access_recovery_reminder( |
|
|
|
address: &str, |
|
|
|
grantee_name: &str, |
|
|
|
atype: &str, |
|
|
@ -341,10 +341,10 @@ pub fn send_emergency_access_recovery_reminder( |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_emergency_access_recovery_rejected(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
|
pub async fn send_emergency_access_recovery_rejected(address: &str, grantor_name: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/emergency_access_recovery_rejected", |
|
|
|
json!({ |
|
|
@ -353,10 +353,10 @@ pub fn send_emergency_access_recovery_rejected(address: &str, grantor_name: &str |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_emergency_access_recovery_timed_out(address: &str, grantee_name: &str, atype: &str) -> EmptyResult { |
|
|
|
pub async fn send_emergency_access_recovery_timed_out(address: &str, grantee_name: &str, atype: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/emergency_access_recovery_timed_out", |
|
|
|
json!({ |
|
|
@ -366,10 +366,10 @@ pub fn send_emergency_access_recovery_timed_out(address: &str, grantee_name: &st |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_invite_accepted(new_user_email: &str, address: &str, org_name: &str) -> EmptyResult { |
|
|
|
pub async fn send_invite_accepted(new_user_email: &str, address: &str, org_name: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/invite_accepted", |
|
|
|
json!({ |
|
|
@ -379,10 +379,10 @@ pub fn send_invite_accepted(new_user_email: &str, address: &str, org_name: &str) |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult { |
|
|
|
pub async fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/invite_confirmed", |
|
|
|
json!({ |
|
|
@ -391,10 +391,10 @@ pub fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult { |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTime, device: &str) -> EmptyResult { |
|
|
|
pub async fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTime, device: &str) -> EmptyResult { |
|
|
|
use crate::util::upcase_first; |
|
|
|
let device = upcase_first(device); |
|
|
|
|
|
|
@ -409,10 +409,10 @@ pub fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTime, de |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_incomplete_2fa_login(address: &str, ip: &str, dt: &NaiveDateTime, device: &str) -> EmptyResult { |
|
|
|
pub async fn send_incomplete_2fa_login(address: &str, ip: &str, dt: &NaiveDateTime, device: &str) -> EmptyResult { |
|
|
|
use crate::util::upcase_first; |
|
|
|
let device = upcase_first(device); |
|
|
|
|
|
|
@ -428,10 +428,10 @@ pub fn send_incomplete_2fa_login(address: &str, ip: &str, dt: &NaiveDateTime, de |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_token(address: &str, token: &str) -> EmptyResult { |
|
|
|
pub async fn send_token(address: &str, token: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/twofactor_email", |
|
|
|
json!({ |
|
|
@ -440,10 +440,10 @@ pub fn send_token(address: &str, token: &str) -> EmptyResult { |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_change_email(address: &str, token: &str) -> EmptyResult { |
|
|
|
pub async fn send_change_email(address: &str, token: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/change_email", |
|
|
|
json!({ |
|
|
@ -452,10 +452,10 @@ pub fn send_change_email(address: &str, token: &str) -> EmptyResult { |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
pub fn send_test(address: &str) -> EmptyResult { |
|
|
|
pub async fn send_test(address: &str) -> EmptyResult { |
|
|
|
let (subject, body_html, body_text) = get_text( |
|
|
|
"email/smtp_test", |
|
|
|
json!({ |
|
|
@ -463,10 +463,10 @@ pub fn send_test(address: &str) -> EmptyResult { |
|
|
|
}), |
|
|
|
)?; |
|
|
|
|
|
|
|
send_email(address, &subject, body_html, body_text) |
|
|
|
send_email(address, &subject, body_html, body_text).await |
|
|
|
} |
|
|
|
|
|
|
|
fn send_email(address: &str, subject: &str, body_html: String, body_text: String) -> EmptyResult { |
|
|
|
async fn send_email(address: &str, subject: &str, body_html: String, body_text: String) -> EmptyResult { |
|
|
|
let smtp_from = &CONFIG.smtp_from(); |
|
|
|
let email = Message::builder() |
|
|
|
.message_id(Some(format!("<{}@{}>", crate::util::get_uuid(), smtp_from.split('@').collect::<Vec<&str>>()[1]))) |
|
|
@ -475,7 +475,7 @@ fn send_email(address: &str, subject: &str, body_html: String, body_text: String |
|
|
|
.subject(subject) |
|
|
|
.multipart(MultiPart::alternative_plain_html(body_text, body_html))?; |
|
|
|
|
|
|
|
match mailer().send(&email) { |
|
|
|
match mailer().send(email).await { |
|
|
|
Ok(_) => Ok(()), |
|
|
|
// Match some common errors and make them more user friendly
|
|
|
|
Err(e) => { |
|
|
|