oxedyne/fe2o3/fe2o3_mail/src/lib.rs
2.8 KiB, 7 runs
created by r1870400018:9812, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | //! Hematite email implementations. |
| 2 | //! |
| 3 | //! Two layers live here. The sans-io [`message`] module reads a message from bytes and |
| 4 | //! builds a draft into bytes, owning no socket and no clock, so a browser client can use it |
| 5 | //! -- it is behind no feature and drags in nothing but `fe2o3_core` and `fe2o3_text`. |
| 6 | //! |
| 7 | //! The server layer is the on-disk implementations of the trait surface (`MailStore`, |
| 8 | //! `UserStore`) that lives in `fe2o3_net` alongside the SMTP and IMAP servers that consume |
| 9 | //! it -- a Maildir-backed mailbox store and a `passwd`-style user file -- plus the outbound |
| 10 | //! spool. The store and the user file pull in `fe2o3_net`, which does not build for |
| 11 | //! `wasm32-unknown-unknown`, so they sit behind the `server` feature (on by default). |
| 12 | |
| 13 | #![forbid(unsafe_code)] |
| 14 | |
| 15 | pub mod message; |
| 16 | |
| 17 | #[cfg(feature = "server")] |
| 18 | pub mod maildir; |
| 19 | pub mod outbound; |
| 20 | #[cfg(feature = "server")] |
| 21 | pub mod passwd; |
| 22 | |
| 23 | use oxedyne_fe2o3_core::prelude::*; |
| 24 | |
| 25 | |
| 26 | /// An addressable email recipient, sender or reply-to target. |
| 27 | /// |
| 28 | /// Wrapping the raw string in a newtype makes it harder to accidentally |
| 29 | /// pass a display name or subject line where an address is expected, |
| 30 | /// and gives a natural hook for future address validation. |
| 31 | #[derive(Clone, Debug, Eq, PartialEq)] |
| 32 | pub struct EmailAddress { |
| 33 | /// Raw address in `local@domain` form. Not validated at construction; |
| 34 | /// implementations may validate at send time. |
| 35 | pub raw: String, |
| 36 | } |
| 37 | |
| 38 | impl EmailAddress { |
| 39 | /// Wrap a raw string as an email address. |
| 40 | pub fn new<S: Into<String>>(raw: S) -> Self { |
| 41 | Self { raw: raw.into() } |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | /// A plain-text email message ready for delivery. |
| 46 | #[derive(Clone, Debug)] |
| 47 | pub struct EmailMessage { |
| 48 | /// Envelope sender. |
| 49 | pub from: EmailAddress, |
| 50 | /// Envelope recipients. |
| 51 | pub to: Vec<EmailAddress>, |
| 52 | /// RFC 5322 subject, plain-text. |
| 53 | pub subject: String, |
| 54 | /// Plain-text body. |
| 55 | pub body: String, |
| 56 | } |
| 57 | |
| 58 | impl EmailMessage { |
| 59 | /// Construct a one-recipient plain-text message. |
| 60 | pub fn new<S: Into<String>>( |
| 61 | from: EmailAddress, |
| 62 | to: EmailAddress, |
| 63 | subject: S, |
| 64 | body: S, |
| 65 | ) |
| 66 | -> Self |
| 67 | { |
| 68 | Self { |
| 69 | from, |
| 70 | to: vec![to], |
| 71 | subject: subject.into(), |
| 72 | body: body.into(), |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | /// Send-side trait for pushing an `EmailMessage` out to a recipient. |
| 78 | pub trait EmailSender: Clone + Send + Sync + 'static { |
| 79 | /// Deliver a fully-constructed message to its envelope recipients. |
| 80 | fn send(&self, msg: &EmailMessage) -> Outcome<()>; |
| 81 | } |
| 82 | |
| 83 | /// Null sender that discards every message. Useful in tests. |
| 84 | #[derive(Clone, Debug, Default)] |
| 85 | pub struct NullEmailSender; |
| 86 | |
| 87 | impl EmailSender for NullEmailSender { |
| 88 | fn send(&self, _msg: &EmailMessage) -> Outcome<()> { |
| 89 | Ok(()) |
| 90 | } |
| 91 | } |