1 parent
9003a50eb4
commit
2486856799
21 files changed
+538
-30
No files matched your search
+63
-4
@@ -268,6 +268,22 @@ pub struct RealImapClient {
|
||||
pool: super::pool::ConnectionPool,
|
||||
}
|
||||
|
||||
fn resolve_message_date(
|
||||
envelope_date: Option<String>,
|
||||
internal_date: Option<String>,
|
||||
) -> Option<String> {
|
||||
envelope_date
|
||||
.and_then(|value| {
|
||||
let trimmed = value.trim();
|
||||
if trimmed.is_empty() || mail_parser::DateTime::parse_rfc822(trimmed).is_none() {
|
||||
None
|
||||
} else {
|
||||
Some(trimmed.to_string())
|
||||
}
|
||||
})
|
||||
.or_else(|| internal_date.filter(|value| !value.trim().is_empty()))
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ImapClient for RealImapClient {
|
||||
async fn capabilities(&self, creds: &ImapCredentials) -> Result<Vec<String>, ImapError> {
|
||||
@@ -380,7 +396,7 @@ impl ImapClient for RealImapClient {
|
||||
let mut fetch_stream = session
|
||||
.uid_fetch(
|
||||
uid_range,
|
||||
"(UID ENVELOPE FLAGS BODYSTRUCTURE RFC822.SIZE BODY.PEEK[HEADER.FIELDS (Message-ID In-Reply-To References Content-Class x-ms-exchange-generated-message-class)])",
|
||||
"(UID ENVELOPE INTERNALDATE FLAGS BODYSTRUCTURE RFC822.SIZE BODY.PEEK[HEADER.FIELDS (Message-ID In-Reply-To References Content-Class x-ms-exchange-generated-message-class)])",
|
||||
)
|
||||
.await
|
||||
.map_err(map_imap_error)?;
|
||||
@@ -405,6 +421,7 @@ impl ImapClient for RealImapClient {
|
||||
let raw_header_bytes = fetch.header();
|
||||
let parsed_threading = raw_header_bytes
|
||||
.and_then(|raw| mail_parser::MessageParser::default().parse(raw));
|
||||
let internal_date = fetch.internal_date().map(|value| value.to_rfc2822());
|
||||
|
||||
let (subject, from, to, cc, date) = if let Some(env) = fetch.envelope() {
|
||||
let subject = env.subject.as_ref().map(|b| decode_header_bytes(b));
|
||||
@@ -427,11 +444,12 @@ impl ImapClient for RealImapClient {
|
||||
.map(|addrs| addrs.iter().map(imap_address_to_email).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
let date = env
|
||||
let envelope_date = env
|
||||
.date
|
||||
.as_ref()
|
||||
.and_then(|b| std::str::from_utf8(b).ok())
|
||||
.map(|s| s.to_string());
|
||||
.map(str::to_string);
|
||||
let date = resolve_message_date(envelope_date, internal_date.clone());
|
||||
|
||||
(subject, from, to, cc, date)
|
||||
} else {
|
||||
@@ -440,7 +458,13 @@ impl ImapClient for RealImapClient {
|
||||
folder = %folder,
|
||||
"ENVELOPE missing for message, headers will be empty until body is fetched"
|
||||
);
|
||||
(None, vec![], vec![], vec![], None)
|
||||
(
|
||||
None,
|
||||
vec![],
|
||||
vec![],
|
||||
vec![],
|
||||
resolve_message_date(None, internal_date.clone()),
|
||||
)
|
||||
};
|
||||
|
||||
let message_id = parsed_threading
|
||||
@@ -1337,3 +1361,38 @@ impl ImapClient for RealImapClient {
|
||||
Ok(supported)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod date_resolution_tests {
|
||||
use super::resolve_message_date;
|
||||
|
||||
#[test]
|
||||
fn uses_internal_date_when_message_date_is_missing() {
|
||||
assert_eq!(
|
||||
resolve_message_date(None, Some("Tue, 3 Nov 2026 14:38:39 +0100".to_string())),
|
||||
Some("Tue, 3 Nov 2026 14:38:39 +0100".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uses_internal_date_when_message_date_is_invalid() {
|
||||
assert_eq!(
|
||||
resolve_message_date(
|
||||
Some("not-a-date".to_string()),
|
||||
Some("Tue, 3 Nov 2026 14:38:39 +0100".to_string())
|
||||
),
|
||||
Some("Tue, 3 Nov 2026 14:38:39 +0100".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keeps_valid_message_date() {
|
||||
assert_eq!(
|
||||
resolve_message_date(
|
||||
Some("Mon, 2 Nov 2026 10:00:00 +0100".to_string()),
|
||||
Some("Tue, 3 Nov 2026 14:38:39 +0100".to_string())
|
||||
),
|
||||
Some("Mon, 2 Nov 2026 10:00:00 +0100".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user