Files
ElyOffice/crates/ely-mail-engine/tests/mime_edges.rs
T
ZacharyZhang-NYandClaude Opus 5.5 fe90221c11 C12.2: read and write MIME by the tree
The reader walks the MIME tree with its container context: alternative
picks versions, related finds its root by start, attached multiparts
stay whole, digest children are messages. Nesting deeper than 64
levels, counting enclosed messages, is refused, and over-deep parse
results are taken apart iteratively so dropping them cannot overflow
the stack. Composite parts with a Content-ID are cid targets.

The writer keeps attachment parameters and Content-IDs, writes
multipart and message attachments unencoded, and makes its own
Message-ID. SMTP adds BODY=8BITMIME for 8-bit bodies and SMTPUTF8
when any header block at any depth is 8-bit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 17:35:05 -04:00

174 lines
4.9 KiB
Rust

use ely_mail_engine::{Error, read};
/// Lines joined with CRLF, as servers send them.
fn crlf(lines: &[&str]) -> Vec<u8> {
lines.join("\r\n").into_bytes()
}
/// `levels` multipart/mixed containers around one text part.
fn nested(levels: usize) -> Vec<u8> {
let mut lines = Vec::new();
for level in 0..levels {
lines.push(format!("Content-Type: multipart/mixed; boundary=b{level}"));
lines.push(String::new());
lines.push(format!("--b{level}"));
}
lines.push("Content-Type: text/plain".into());
lines.push(String::new());
lines.push("deep".into());
for level in (0..levels).rev() {
lines.push(format!("--b{level}--"));
}
lines.push(String::new());
lines.join("\r\n").into_bytes()
}
#[test]
fn deep_nesting_is_an_error_not_a_crash() {
let err = read(&nested(2048)).unwrap_err();
assert!(
matches!(&err, Error::Mime(text) if text.contains("deeper than 64")),
"{err}"
);
let mail = read(&nested(63)).unwrap();
assert_eq!(mail.text.as_deref(), Some("deep"));
}
#[test]
fn multibyte_charsets_decode() {
let mail = read(&crlf(&[
"Subject: =?GB2312?B?1tDOxA==?=",
"Content-Type: text/plain; charset=gb2312",
"Content-Transfer-Encoding: base64",
"",
"1tDOxA==",
"",
]))
.unwrap();
assert_eq!(mail.subject.as_deref(), Some("中文"));
assert_eq!(mail.text.as_deref(), Some("中文"));
}
#[test]
fn a_related_root_marked_attachment_is_still_the_body() {
let mail = read(&crlf(&[
"Content-Type: multipart/related; boundary=r; type=\"text/html\"",
"",
"--r",
"Content-Type: text/html",
"Content-Disposition: attachment; filename=body.html",
"",
"<p>root</p>",
"--r",
"Content-Type: image/png",
"Content-ID: <img@example.com>",
"",
"png",
"--r--",
"",
]))
.unwrap();
assert_eq!(mail.html.as_deref(), Some("<p>root</p>"));
assert!(mail.attachments.is_empty());
let ids: Vec<_> = mail
.inline
.iter()
.map(|p| p.content_id.as_deref())
.collect();
assert_eq!(ids, [Some("img@example.com")]);
}
#[test]
fn a_composite_related_resource_keeps_its_entity() {
let mail = read(&crlf(&[
"Content-Type: multipart/related; boundary=r; type=\"text/html\"",
"",
"--r",
"Content-Type: text/html",
"",
"<p>root</p>",
"--r",
"Content-Type: multipart/alternative; boundary=a",
"Content-ID: <entity@example.com>",
"Content-Disposition: inline; filename=entity.mime",
"",
"--a",
"Content-Type: text/plain",
"",
"inner",
"--a--",
"--r--",
"",
]))
.unwrap();
assert_eq!(mail.html.as_deref(), Some("<p>root</p>"));
assert!(mail.attachments.is_empty());
let [entity] = mail.inline.as_slice() else {
panic!("{:?}", mail.inline)
};
assert_eq!(entity.content_id.as_deref(), Some("entity@example.com"));
assert_eq!(entity.name.as_deref(), Some("entity.mime"));
assert_eq!(entity.content_type, "multipart/alternative");
let bytes = String::from_utf8(entity.bytes.clone()).unwrap();
assert!(
bytes.starts_with("Content-Type: multipart/alternative"),
"{bytes}"
);
assert!(bytes.contains("inner"), "{bytes}");
}
#[test]
fn a_text_part_with_a_content_id_is_a_cid_target() {
let mail = read(&crlf(&[
"Content-Type: multipart/mixed; boundary=b",
"",
"--b",
"Content-Type: text/plain",
"",
"body",
"--b",
"Content-Type: text/html; charset=utf-8",
"Content-ID: <frame@example.com>",
"Content-Disposition: inline",
"",
"<p>frame</p>",
"--b--",
"",
]))
.unwrap();
assert_eq!(mail.text.as_deref(), Some("body"));
let [frame] = mail.inline.as_slice() else {
panic!("{:?}", mail.inline)
};
assert_eq!(frame.content_id.as_deref(), Some("frame@example.com"));
assert_eq!(frame.content_type, "text/html");
assert_eq!(frame.params, [("charset".to_owned(), "utf-8".to_owned())]);
assert_eq!(frame.bytes, b"<p>frame</p>");
}
#[test]
fn an_unknown_disposition_is_an_attachment() {
let mail = read(&crlf(&[
"Content-Type: multipart/mixed; boundary=b",
"",
"--b",
"Content-Type: text/plain",
"",
"body",
"--b",
"Content-Type: text/plain",
"Content-Disposition: x-file; filename=file.txt",
"",
"private attachment",
"--b--",
"",
]))
.unwrap();
assert_eq!(mail.text.as_deref(), Some("body"));
let [file] = mail.attachments.as_slice() else {
panic!("{:?}", mail.attachments)
};
assert_eq!(file.name.as_deref(), Some("file.txt"));
assert_eq!(file.bytes, b"private attachment");
}