Skip to content

Commit e59cfcd

Browse files
committed
log information about sent emails
1 parent d1ecef4 commit e59cfcd

File tree

1 file changed

+49
-14
lines changed

1 file changed

+49
-14
lines changed

src/email.rs

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ use std::sync::Mutex;
33

44
use crate::util::errors::{server_error, AppResult};
55

6+
use crate::middleware::log_request::add_custom_metadata;
67
use lettre::transport::file::FileTransport;
78
use lettre::transport::smtp::authentication::{Credentials, Mechanism};
89
use lettre::transport::smtp::SmtpTransport;
910
use lettre::{Message, Transport};
11+
use rand::distributions::{Alphanumeric, DistString};
1012

1113
#[derive(Debug)]
1214
pub 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

Comments
 (0)