From fed28c3ecadffdfc5be38895872590b6b0cfdb20 Mon Sep 17 00:00:00 2001 From: rustmailer Date: Wed, 28 Jan 2026 13:19:33 +0800 Subject: [PATCH] fix: add tolerant HTML-to-text extraction (#141) --- src/modules/envelope/extractor.rs | 11 +++-------- src/modules/utils/html.rs | 28 ++++++++++++++++++++++++++++ src/modules/utils/mod.rs | 1 + 3 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 src/modules/utils/html.rs diff --git a/src/modules/envelope/extractor.rs b/src/modules/envelope/extractor.rs index d428bdb..9a9d58e 100644 --- a/src/modules/envelope/extractor.rs +++ b/src/modules/envelope/extractor.rs @@ -21,6 +21,7 @@ use crate::modules::envelope::utils::normalize_subject; use crate::modules::error::code::ErrorCode; use crate::modules::error::BichonResult; use crate::modules::utils::create_hash; +use crate::modules::utils::html::extract_text; use crate::{calculate_hash, raise_error, utc_now}; use crate::{id, modules::indexer::envelope::Envelope}; use async_imap::types::Fetch; @@ -48,10 +49,7 @@ pub fn extract_envelope(fetch: &Fetch, account_id: u64, mailbox_id: u64) -> Bich let text = if let Some(text) = message.body_text(0).map(|cow| cow.into_owned()) { text } else if let Some(html) = message.body_html(0).map(|cow| cow.into_owned()) { - html2text::config::plain() - .allow_width_overflow() - .string_from_read(html.as_bytes(), 100) - .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))? + extract_text(html) } else { String::new() }; @@ -150,10 +148,7 @@ pub fn extract_envelope_from_eml( let text = if let Some(text) = message.body_text(0).map(|cow| cow.into_owned()) { text } else if let Some(html) = message.body_html(0).map(|cow| cow.into_owned()) { - html2text::config::plain() - .allow_width_overflow() - .string_from_read(html.as_bytes(), 100) - .map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))? + extract_text(html) } else { String::new() }; diff --git a/src/modules/utils/html.rs b/src/modules/utils/html.rs new file mode 100644 index 0000000..b933fbd --- /dev/null +++ b/src/modules/utils/html.rs @@ -0,0 +1,28 @@ +use std::panic; +use tracing::error; + +pub fn extract_text(html: String) -> String { + let result = panic::catch_unwind(|| { + html2text::config::plain() + .allow_width_overflow() + .string_from_read(html.as_bytes(), 100) + }); + + match result { + Ok(Ok(text)) => text, + Ok(Err(err)) => { + error!("html2text error: {}", err); + html + } + Err(err) => { + if let Some(s) = err.downcast_ref::<&str>() { + error!("html2text panic: {}", s); + } else if let Some(s) = err.downcast_ref::() { + error!("html2text panic: {}", s); + } else { + error!("html2text panic: unknown error"); + } + html + } + } +} diff --git a/src/modules/utils/mod.rs b/src/modules/utils/mod.rs index 68b3017..57610b7 100644 --- a/src/modules/utils/mod.rs +++ b/src/modules/utils/mod.rs @@ -26,6 +26,7 @@ use rand::{rng, Rng}; use super::error::code::ErrorCode; pub mod encrypt; +pub mod html; pub mod net; pub mod rate_limit; pub mod shutdown;