Oregami
Repositories/oxedyne/fe2o3

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
15pub mod message;
16
17#[cfg(feature = "server")]
18pub mod maildir;
19pub mod outbound;
20#[cfg(feature = "server")]
21pub mod passwd;
22
23use 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)]
32pub 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
38impl 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)]
47pub 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
58impl 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.
78pub 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)]
85pub struct NullEmailSender;
86
87impl EmailSender for NullEmailSender {
88 fn send(&self, _msg: &EmailMessage) -> Outcome<()> {
89 Ok(())
90 }
91}