Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

as_string() produces empty line in header that can cause MTA rejection #59

Open
Hocuri opened this issue Dec 30, 2020 · 1 comment · May be fixed by #60
Open

as_string() produces empty line in header that can cause MTA rejection #59

Hocuri opened this issue Dec 30, 2020 · 1 comment · May be fixed by #60

Comments

@Hocuri
Copy link

Hocuri commented Dec 30, 2020

Under some circumstances a the header in the final email contains an empty line. We are building an email client, and some messages are rejected because of this: deltachat/deltachat-core-rust#2118

This test reproduces the problem:

#[test]
fn test_no_empty_directly() {
    let to_tuples = vec![
        ("Nnnn", "[email protected]"),
        ("😀 ttttttt", "[email protected]"),
        ("dididididididi", "[email protected]"),
        ("Ttttttt", "[email protected]"),
        ("Mmmmm", "[email protected]"),
        ("Zzzzzz", "[email protected]"),
        ("Xyz", "[email protected]"),
        ("", "[email protected]"),
        ("qqqqqq", "[email protected]"),
        ("bbbb", "[email protected]"),
        ("", "[email protected]"),
        ("rqrqrqrqr", "[email protected]"),
        ("tttttttt", "[email protected]"),
        ("", "[email protected]"),
    ];
    let mut to = Vec::new();
    for (name, addr) in to_tuples {
        if name.is_empty() {
            to.push(Address::new_mailbox(addr.to_string()));
        } else {
            to.push(Address::new_mailbox_with_name(
                name.to_string(),
                addr.to_string(),
            ));
        }
    }

    let mut message = email::MimeMessage::new_blank_message();
    message.headers.insert(
        (
            "Content-Type".to_string(),
            "text/plain; charset=utf-8; format=flowed; delsp=no".to_string(),
        )
            .into(),
    );
    message
        .headers
        .insert(Header::new_with_value("To".into(), to).unwrap());
    message.body = "Hi".to_string();

    println!("======= HEADERS BEFORE CALL TO AS_STRING: =======");
    for h in message.headers.iter() {
        println!("{}", h);
    }
    let msg = message.as_string(); // <-- seems like here the empty line is introduced

    let header_end = msg.find("Hi").unwrap();
    let headers = msg[0..header_end].trim();
    println!(
        "======= HEADERS AFTER CALL TO AS_STRING: =======\n{}\n",
        headers
    );
    assert!(!headers.lines().any(|l| l.trim().is_empty())); // <--  panics
}

Output:

======= HEADERS BEFORE CALL TO AS_STRING: =======
Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no
To: Nnnn <[email protected]>, 
        =?utf-8?q?=F0=9F=98=80_ttttttt?= <[email protected]>, 
        dididididididi <[email protected]>, Ttttttt <[email protected]>, 
        Mmmmm <[email protected]>, Zzzzzz <[email protected]>, 
        Xyz <[email protected]>, <[email protected]>, qqqqqq <[email protected]>, 
        bbbb <[email protected]>, <[email protected]>, rqrqrqrqr <[email protected]>, 
        tttttttt <[email protected]>, <[email protected]>
======= HEADERS AFTER CALL TO AS_STRING: =======
Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no
To: Nnnn <[email protected]>, 
        =?utf-8?q?=F0=9F=98=80_ttttttt?= <[email protected]>, 
        dididididididi <[email protected]>, Ttttttt <[email protected]>, 
        Mmmmm <[email protected]>, Zzzzzz <[email protected]>, 
        Xyz <[email protected]>, <[email protected]>, qqqqqq <[email protected]>, 
        bbbb <[email protected]>, <[email protected]>, rqrqrqrqr <[email protected]>,

        tttttttt <[email protected]>, <[email protected]>

thread 'mimefactory::tests::test_no_empty_directly' panicked at 'assertion failed: !headers.lines().any(|l| l.trim().is_empty())', src/mimefactory.rs:1649:9
@Hocuri
Copy link
Author

Hocuri commented Jan 1, 2021

I just realized that the test doesn't correctly reproduce the problem in the newest version, but it's still there. Here is a test that should work:

#[test]
fn test_emit_no_empty_lines() {
    // Please don't change anything to the intendation:
    let header = "To: Nnnn <[email protected]>, 
=?utf-8?q?=F0=9F=98=80_ttttttt?= <[email protected]>, 
dididididididi <[email protected]>, Ttttttt <[email protected]>, 
Mmmmm <[email protected]>, Zzzzzz <[email protected]>, 
Xyz <[email protected]>, <[email protected]>, qqqqqq <[email protected]>, 
bbbb <[email protected]>, <[email protected]>, rqrqrqrqr <[email protected]>, 
tttttttt <[email protected]>, <[email protected]>";

    let mut builder = Rfc5322Builder::new();

    builder.emit_folded(&header.to_string()[..]);
    builder.emit_raw("\r\n");
    builder.emit_raw("\r\n");

    let res = builder.result().trim();
    println!("{}", res);
    assert!(!res.lines().any(|l| l.trim().is_empty())); // <--  panics
}

@Hocuri Hocuri linked a pull request Jan 1, 2021 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant