feat: update email logic to subject not user +
This commit is contained in:
parent
ede986080a
commit
6a652ed4f3
5 changed files with 136 additions and 27 deletions
|
|
@ -101,9 +101,16 @@ pub async fn post_question(
|
|||
|
||||
let notify_email = state.notify_email.clone();
|
||||
let mail_domain = state.mail_domain.clone();
|
||||
let qa_reply_domain = state.qa_reply_domain.clone();
|
||||
let question_text = body.question.clone();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
if let Err(e) = email::send_notification(id, &question_text, ¬ify_email, &mail_domain) {
|
||||
if let Err(e) = email::send_notification(
|
||||
id,
|
||||
&question_text,
|
||||
¬ify_email,
|
||||
&mail_domain,
|
||||
&qa_reply_domain,
|
||||
) {
|
||||
eprintln!("Failed to send notification: {e}");
|
||||
}
|
||||
});
|
||||
|
|
@ -163,10 +170,20 @@ impl Recipient {
|
|||
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct MtaHookBody {
|
||||
#[serde(default)]
|
||||
pub subject: Option<String>,
|
||||
#[serde(default)]
|
||||
pub headers: MessageHeaders,
|
||||
#[serde(default)]
|
||||
pub contents: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct MessageHeaders {
|
||||
#[serde(default)]
|
||||
pub subject: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct MtaHookResponse {
|
||||
pub action: &'static str,
|
||||
|
|
@ -209,11 +226,13 @@ fn webhook_secret_matches(headers: &HeaderMap, expected_secret: &str) -> bool {
|
|||
password == expected_secret
|
||||
}
|
||||
|
||||
fn extract_qa_reply(payload: &MtaHookPayload) -> Option<(i64, String)> {
|
||||
fn extract_qa_reply(payload: &MtaHookPayload, expected_domain: &str) -> Option<(i64, String)> {
|
||||
if !payload.messages.is_empty() {
|
||||
for message in &payload.messages {
|
||||
if let Some(reply) = extract_qa_reply_from_message(
|
||||
&message.envelope.to,
|
||||
expected_domain,
|
||||
message.message.subject.as_deref().or(message.message.headers.subject.as_deref()),
|
||||
if message.message.contents.is_empty() {
|
||||
&message.contents
|
||||
} else {
|
||||
|
|
@ -226,20 +245,41 @@ fn extract_qa_reply(payload: &MtaHookPayload) -> Option<(i64, String)> {
|
|||
return None;
|
||||
}
|
||||
|
||||
extract_qa_reply_from_message(&payload.envelope.to, &payload.message.contents)
|
||||
extract_qa_reply_from_message(
|
||||
&payload.envelope.to,
|
||||
expected_domain,
|
||||
payload
|
||||
.message
|
||||
.subject
|
||||
.as_deref()
|
||||
.or(payload.message.headers.subject.as_deref()),
|
||||
&payload.message.contents,
|
||||
)
|
||||
}
|
||||
|
||||
fn extract_qa_reply_from_message(
|
||||
recipients: &[Recipient],
|
||||
expected_domain: &str,
|
||||
subject: Option<&str>,
|
||||
contents: &str,
|
||||
) -> Option<(i64, String)> {
|
||||
let qa_recipient = recipients.iter().find(|recipient| {
|
||||
let local = recipient.address().split('@').next().unwrap_or("");
|
||||
local.starts_with("qa+")
|
||||
let _qa_recipient = recipients.iter().find(|recipient| {
|
||||
let address = recipient.address();
|
||||
let Some((local, domain)) = address.rsplit_once('@') else {
|
||||
return false;
|
||||
};
|
||||
|
||||
local.eq_ignore_ascii_case("qa") && domain.eq_ignore_ascii_case(expected_domain)
|
||||
})?;
|
||||
|
||||
let id = email::extract_id_from_address(qa_recipient.address()).ok()?;
|
||||
let body = email::strip_quoted_text(contents);
|
||||
let subject = subject.map(ToOwned::to_owned).or_else(|| {
|
||||
contents
|
||||
.replace("\r\n", "\n")
|
||||
.lines()
|
||||
.find_map(|line| line.strip_prefix("Subject: ").map(ToOwned::to_owned))
|
||||
})?;
|
||||
let id = email::extract_id_from_subject(&subject).ok()?;
|
||||
let body = email::extract_plain_text_body(contents);
|
||||
if body.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -257,7 +297,7 @@ pub async fn webhook(
|
|||
return Err((StatusCode::UNAUTHORIZED, "invalid secret".to_string()));
|
||||
}
|
||||
|
||||
if let Some((id, body)) = extract_qa_reply(&payload) {
|
||||
if let Some((id, body)) = extract_qa_reply(&payload, &state.qa_reply_domain) {
|
||||
let db = state
|
||||
.db
|
||||
.lock()
|
||||
|
|
@ -290,11 +330,12 @@ mod tests {
|
|||
"envelope": {
|
||||
"to": [
|
||||
{
|
||||
"address": "qa+42@extremist.software"
|
||||
"address": "qa@extremist.software"
|
||||
}
|
||||
]
|
||||
},
|
||||
"message": {
|
||||
"subject": "Re: 42 - hello",
|
||||
"contents": "This is the answer.\n\nOn earlier mail wrote:\n> quoted"
|
||||
}
|
||||
}"#,
|
||||
|
|
@ -302,7 +343,7 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
extract_qa_reply(&payload),
|
||||
extract_qa_reply(&payload, "extremist.software"),
|
||||
Some((42, "This is the answer.".to_string()))
|
||||
);
|
||||
}
|
||||
|
|
@ -314,7 +355,10 @@ mod tests {
|
|||
"messages": [
|
||||
{
|
||||
"envelope": {
|
||||
"to": ["qa+7@extremist.software"]
|
||||
"to": ["qa@extremist.software"]
|
||||
},
|
||||
"message": {
|
||||
"subject": "Re: 7 - legacy"
|
||||
},
|
||||
"contents": "Legacy answer"
|
||||
}
|
||||
|
|
@ -324,7 +368,7 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
extract_qa_reply(&payload),
|
||||
extract_qa_reply(&payload, "extremist.software"),
|
||||
Some((7, "Legacy answer".to_string()))
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue