niax / rust-email Goto Github PK
View Code? Open in Web Editor NEWImplementation of MIME Messages for Rust
License: MIT License
Implementation of MIME Messages for Rust
License: MIT License
The FromStr trait has changed so much that rust-email's impl breaks. This is probably a good time to fix #7 too.
FromStr parses the whole string into the address field. But if I have a from field like "Pyry Kontio [email protected]", I'd expect it parse the first part into the name field and the part inside the <> into the address field.
If it seems hard to break current functionality, Mailbox would should at least provide another method for attempting to parse this. This surprising behaviour breaks some downstream crates too โ I came here because I got noticed this behaviour on Lettre.
Rust's nightly as of 2015-01-09 has warnings for usage of unstable APIs on by default - showing up APIs that may be going away shortly. It'd be nice to be ahead of the curve for a change. See the build log for 0.0.7 for a full list.
as_slice
, slice
, slice_from
, slice_to
usages should use slicing syntax or otherstd::fmt::Show
/std::fmt::String
is still unstable - awaiting outcome from upstreamrange
My simple test looks like this:
#[test]
fn test_long_lines() {
let mail_str = "From:iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii\r\n\r\n\r\n";
let mime_msg = MimeMessage::parse(mail_str);
// assert!(mime_msg.is_err()); shouldn't the parser fail here with some sort of error?
let from_head: ParsingResult<String> = mime_msg.unwrap().headers.get_value("From".to_owned());
assert!(from_head.is_err());
}
Shouldn't MimeMessage::parse() return some kind of Error, stating that the line was too long or did i misread the RFC? According to https://tools.ietf.org/html/rfc5322#section-2.1.1 every line MUST be smaller then 998". Clearly my mail_str is not RFC compliant, but when receiving mails i can't rely on the comformance of the mail to the RFC.
possibly, add more examples?
Let me know if you need an example.
While removing usages of unstable features, I've put quite a lot of unwrap
s in the code. I don't think the code now panics more on bad input than it did before (since the unstable APIs paniced themselves), but still.
I'm experimenting with rust-email for an e-mail client project.
I need to read the headers from many messages (ie a mailbox), without having to read in and parse the entire (possibly huge) e-mail bodies, to display a message index.
The best option I can see so far is to manually read chunks from each message and scan myself until I can see a double line break, then feed that data into an Rfc5322
and call consume_header() repeatedly. Which is fine, but it's a shame to have to duplicate a small part of the parsing. It'd be nice for me if the the parser could work from a std::io::Read
or std::io::BufRead
, say, and so take either a file or string. (Acknowledging that UTF-8 handling needs doing somewhere!)
I'd be interested in suggestions of better ways to do it, or changes/additions to this crate which might happen in future.
While the RFCs clearly specify CRLF endings in emails/MIME boundaries, it turns out that e-mails are normally written to disk by the MTA with just LF on Linux/Unix systems.
I would therefore find it handy to have an LF option, or simply to allow both. It would be a shame to have to convert LFs back to CRLF before feeding to MimeMessage, especially with large messages. :-)
It should be possible to set a MimeMessage's body using an &str
and have the message handle its own encoding, not unlike the existing decoded_body_bytes
and decoded_body_string
functions.
Implement as per RFC822 Section 5.
I think HeaderMap::get
should be case insensitive, eg headers.get("Content-Transfer-Encoding")
should still work if the actual header is spelled "Content-transfer-encoding". I guess I would go for ordered_headers
having the original case and the headers
HashMap storing lower-cased keys (translating whenever it's used).
See the advisory at: https://rustsec.org/advisories/RUSTSEC-2020-0159.html
There is currently no fixed release of chrono. It's unclear to me if chrono is still maintained. I'm not sure if replacing it is an option?
MIME messages with final 'encapsulation' boundary (ending in --) parse incorrectly. The last boundary is included as part of the last MIME part.
If this is indeed an issue (and not me missing something), I'll be happy to fix it.
Just as a heads up, it looks like rust-email will stop working in rust 1.5:
/email-0.0.12/src/header.rs:24:5: 24:58 warning: the trait `core::marker::Sized` is not implemented for the type `Self` [E0277]
/email-0.0.12/src/header.rs:24 fn from_header(value: String) -> ParsingResult<Self>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/email-0.0.12/src/header.rs:24:5: 24:58 help: run `rustc --explain E0277` to see a detailed explanation
/email-0.0.12/src/header.rs:24:5: 24:58 note: `Self` does not have a constant size known at compile-time
/email-0.0.12/src/header.rs:24:5: 24:58 note: this warning results from recent bug fixes and clarifications; it will become a HARD ERROR in the next release. See RFC 1214 for details.
/email-0.0.12/src/header.rs:24 fn from_header(value: String) -> ParsingResult<Self>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/email-0.0.12/src/header.rs:24:5: 24:58 note: required by `core::result::Result`
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
Rc
prevents the datatypes defined in this crate from being Send
. This affects some downstream crates that use the data types in this crate for implementing email-related stuff. Sometimes these things need to be send between threads (for example, when you have one mailer thread and you prepare emails in many threads and send them to the mailer thread), so this hinders the usability of the types defined here.
I've received an e-mail with a (UTF-8) em dash in the subject header, which causes consume_unstructured()
to loop forever. A nearly minimal example which triggers the issue (tested using the parse_email example):
00000000 53 75 62 6a 65 63 74 3a 20 e2 80 94 20 61 6c 6c |Subject: ... all|
00000010 0a |.|
The m-dash fails the is_vchar()
test so the consume_while()
doesn't make any progress.
Please add #[derive(PartialEq, Eq, Copy, Clone, Debug)]
so the error could be compared in tests of other libraries/apps that use your library, or be copied.
Thanks in advance!
https://github.com/niax/rust-email/blob/master/src/results.rs#L4
Headers should (as required) use RFC2047 encoding when being coerced into a string for inclusion in a MimeMessage.
It should:
It's probably nice to know if and why the parse failed at some point, rather than just returning None
.
This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic
on IRC to discuss.
You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.
TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.
The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.
Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.
To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.
and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):
// Copyright 2016 rust-email Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.
Be sure to add the relevant LICENSE-{MIT,APACHE}
files. You can copy these
from the Rust repo for a plain-text
version.
And don't forget to update the license
metadata in your Cargo.toml
to:
license = "MIT OR Apache-2.0"
I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!
To agree to relicensing, comment with :
I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.
Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.
This is because of the just-in-time generation of a boundary & Content-Type headers.
Perhaps these should be moved out into a separate function which can be called if required by the user.
It would be great to add this MIME multipart subtypes, so that it's possible to create MIME encrypted emails.
Use cargo doc --no-deps
to generate only for this module.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.