diff --git a/crates/mailparsing/src/mimepart.rs b/crates/mailparsing/src/mimepart.rs index 07a2230b..8f29d48c 100644 --- a/crates/mailparsing/src/mimepart.rs +++ b/crates/mailparsing/src/mimepart.rs @@ -16,13 +16,17 @@ use std::str::FromStr; use std::sync::Arc; /// Define our own because data_encoding::BASE64_MIME, despite its name, -/// is not RFC2045 compliant, and will not ignore spaces +/// is not RFC2045 compliant, and will not ignore spaces. +/// check_trailing_bits is disabled because real-world MIME producers emit +/// final quantums whose discarded padding bits are non-zero; a strict decoder +/// would reject those otherwise-decodable bodies. const BASE64_RFC2045: data_encoding::Encoding = data_encoding_macro::new_encoding! { symbols: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", padding: '=', ignore: " \r\n\t", wrap_width: 76, wrap_separator: "\r\n", + check_trailing_bits: false, }; #[derive(Debug, Clone, PartialEq)] @@ -2282,4 +2286,16 @@ Body\r } ); } + + /// Test the use case of check_trailing_bits being false. + /// This accepts a final quantum whose discarded padding bits are non-zero, + /// which a strict base64 decoder would reject. + /// For reference, valid base64 is aHRtbD4NCg== + #[test] + fn check_trailing_bits_test() { + // The low 4 trailing bits before `==` are non-zero in this sample. + // With check_trailing_bits=false we should still accept and decode it. + let decoded = BASE64_RFC2045.decode(b"aHRtbD4NCi==").unwrap(); + assert_eq!(decoded, b"html>\r\n"); + } } diff --git a/docs/changelog/main.md b/docs/changelog/main.md index 9e8e035c..2730c56c 100644 --- a/docs/changelog/main.md +++ b/docs/changelog/main.md @@ -202,6 +202,11 @@ startup, that would otherwise lead to rocksdb corrupting itself on the restart *after* the permissions were broken. + * Base64-encoded MIME bodies whose final quantum has non-zero discarded + padding bits are now decoded rather than rejected, matching the + leniency other mail software applies to such non-canonical encodings. + Thanks to @kayozaki! #558 + ## Fixes * An SMTP command line containing bytes that are not valid UTF-8 is now @@ -234,3 +239,4 @@ after it was first persisted are now written back to the meta spool, rather than being silently dropped on the next reload from spool. Thanks to @alexanderwburch! #570 +