duesee / imap-codec

Rock-solid and complete codec for IMAP
Apache License 2.0
37 stars 14 forks source link

Clarify the difference to `imap-proto` crate #322

Closed link2xt closed 1 year ago

link2xt commented 1 year ago

There is an existing crate imap-proto and it is already used in production in Delta Chat via async-imap crate. How does imap-codec compare to imap-proto?

Would be nice to clarify this in the README.

It is not trivial to switch async-imap to imap-proto because it reexports some types, but can still be considered if there are some advantages.

duesee commented 1 year ago

Hey @link2xt! Thanks for the suggestion! There should really be something in the README.

The most significant differences are server-support, the split into imap-codec and imap-types (that should facilitate interoperability), and imap-types' core types (that should provide misuse resistance).

I'll compile a more thorough answer next week!

duesee commented 1 year ago

Btw: I applied for another round of funding and would love to help out with a correct, async, higher-level IMAP library. When things go well, we should definitely talk!

duesee commented 1 year ago

A first attempt: If there is anything specific you want to know (or would like to see mentioned), feel free to ask (or tell me)!

imap-codec in the Rust email ecosystem

imap-codec provides low-level parsing and serialization support for IMAP4rev1, similar to imap-proto. The most significant differences are server support, the split into imap-codec and imap-types, misuse resistance (affecting API design), and (real world) test coverage.

To a certain extent, server-side support is always required because a client must create and serialize Commands. Full server support not only means that you can write IMAP servers with imap-codec but also that we can share data structures, e.g., to send a Command and wait for a command completion Response using the same Tag.

The imap-codec/imap-types split should allow the Rust community to maintain a well-designed set of "pure" IMAP types (free of e.g. "helper types" for parsing) but leave room for custom crates (based on imap-types).[^1] However, the maintenance costs could be higher compared to imap-proto.

Generally, imap-codec has a more extensive API surface than imap-proto and -- depending on personal preference -- may be more challenging to use. However, it guarantees that you never construct invalid messages and aims to make IMAP usable even for people who are no IMAP experts. For example, imap-codec has build-in support for IMAP literals.

imap-codec has a high test coverage and is fuzz-tested to ensure properties such as invertibility, misuse-resistance, etc. Generally, you should be unable to crash the library or generate messages that imap-codec (or another party) can't parse. However, imap-proto has already succeeded in production. For example, it could implement real-world quirks that imap-codec doesn't (yet). Despite extensive testing (against real servers and clients), imap-proto might have a more mature interoperability story. Also, it might implement more of the features that really matter in practice.

[^1]: E.g., an IMF/MIME to BodyStructure crate, a proxy that doesn't do parsing, security tools, etc.

link2xt commented 1 year ago

To a certain extent, server-side support is always required because a client must create and serialize Commands.

This is not clear to me, how generating commands is a server-side feature?

Inability to create invalid commands is certainly a distinguishing feature compared to imap-proto where search queries are just injected into the stream as-is and can be invalid.

duesee commented 1 year ago

This is not clear to me, how generating commands is a server-side feature?

This was not phrased very well...

What I wanted to say:

No matter if implementing a client- or a server, you need the full spectrum of IMAP type definitions. When you send a command with a specific Tag, you expect a command completion response with the same Tag. Thus, commands and responses must work well together (and are best provided by a single crate). imap-types provides this complete set of IMAP type definitions that should be reusable across the Rust ecosystem.

Parsing and serialization are different: As a client developer, you will never parse commands nor serialize responses. As a server developer, you will never serialize commands nor parse responses. Thus, you only need "half of" the spectrum of parsers and serializers. Therefore, this functionality could be provided by separate crates (as long as both use imap-types, of course). imap-codec provides a complete set of serializers and parsers for commands and responses (and might also offer a feature gate to exclude unneeded functionality in the future).

duesee commented 1 year ago

Inability to create invalid commands is certainly a distinguishing feature compared to imap-proto where search queries are just injected into the stream as-is and can be invalid.

It has been a while since I've used imap-proto, but I remember that literal handling wasn't well-supported. (A search query can contain an indefinite amount of literals :-/) The last time I tried, it didn't generate a literal for a non-quotable password. However, I have not seen a server that would choke on this. It's not standard-conforming, but it may be fine. Hard to tell without extensive real-world deployment.

duesee commented 1 year ago

I've added a FAQ to the README. Thanks!