crabmail

Static HTML email archive viewer in Rust
git clone git://git.alexwennerberg.com/crabmail
Log | Files | Refs | README | LICENSE

commit c58574b106eb09a7643736f75cf625c5160a86f2
parent 5f7c757c00d66c56a5f033062de466a964cd2e4f
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Sun, 12 Dec 2021 23:34:52 -0800

mailto links

fun and exciting

Diffstat:
Mcrabmail/Cargo.lock | 8+-------
Mcrabmail/Cargo.toml | 2+-
Mcrabmail/src/main.rs | 22++++++++++++++++++----
Mcrabmail/templates/static/style.css | 5++++-
Mcrabmail/templates/thread.html | 7+++++--
5 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/crabmail/Cargo.lock b/crabmail/Cargo.lock @@ -146,7 +146,7 @@ dependencies = [ "mailparse", "mbox-reader", "pico-args", - "urlencoding", + "url", ] [[package]] @@ -674,12 +674,6 @@ dependencies = [ ] [[package]] -name = "urlencoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b90931029ab9b034b300b797048cf23723400aa757e8a2bfb9d748102f9821" - -[[package]] name = "utf-8" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/crabmail/Cargo.toml b/crabmail/Cargo.toml @@ -12,7 +12,7 @@ html = ["ammonia"] [dependencies] mailparse = "0.13" -urlencoding = "2.1.0" +url = "2" mbox-reader = "0.2.0" #unamaintained, should remove dep pico-args = "0.4.1" askama = "0.10" diff --git a/crabmail/src/main.rs b/crabmail/src/main.rs @@ -3,9 +3,9 @@ use askama::Template; use mailparse::*; use mbox_reader::MboxFile; use std::collections::HashMap; -use std::fmt; -use std::fs::{File, OpenOptions}; +use std::fs::OpenOptions; use std::io::prelude::*; +use url::Url; mod filters; @@ -33,6 +33,20 @@ struct Email { // raw_email: String, } +impl Email { + // mailto:... populated with everything you need + pub fn mailto(&self) -> String { + // TODO configurable + let mut url = Url::parse(&format!("mailto:~aw/flounder@lists.sr.ht")).unwrap(); + url.query_pairs_mut() + .append_pair("cc", &self.from.to_string()); + url.query_pairs_mut().append_pair("in-reply-to", &self.id); + // should get thread subject ideally + url.query_pairs_mut().append_pair("subject", &self.subject); + url.into() + } +} + #[cfg(feature = "html")] fn parse_html_body(email: &ParsedMail) -> String { use ammonia; @@ -133,7 +147,7 @@ fn main() -> Result<()> { // TODO fix borrow checker if let Some(reply) = email.in_reply_to.clone() { match thread_index.get(&reply) { - Some(e) => { + Some(_) => { let d = thread_index.get_mut(&reply).unwrap(); d.push(email.id.clone()); } @@ -147,7 +161,7 @@ fn main() -> Result<()> { let mut thread_roots: Vec<&Email> = email_index .iter() - .filter_map(|(k, v)| { + .filter_map(|(_, v)| { if v.in_reply_to.is_none() { return Some(v); } diff --git a/crabmail/templates/static/style.css b/crabmail/templates/static/style.css @@ -6,7 +6,7 @@ body { font-family: "Roboto", Helvetica, Arial, Sans-serif; word-wrap: break-word; line-height: 1.5; - max-width: 79ch; + max-width: 70ch; padding: 1ch; } @@ -21,6 +21,9 @@ table { border-spacing: 0.5em 0.1em; } .message-sum { margin: 4px; } +.reply { + text-align: right; +} .addr { color: darkblue; } diff --git a/crabmail/templates/thread.html b/crabmail/templates/thread.html @@ -7,12 +7,15 @@ {% for message in messages %} <div id="{{message.id}}" class="message"> <b> - <a href="mailto:{{message.from.addr}}" class="addr">{{message.from}}</a> - <span class="timeago">{{message.date | time_ago}}</span></b> + <a href="mailto:{{message.from.addr}}" class="addr">{{message.from}}</a></b> + <span class="timeago">{{message.date | time_ago}}</span> <a href="#{{message.id}}">🔗</a> <div class="email-body"> {{message.body}} </div> + <div class="reply"> + <a href="{{message.mailto()}}">✉️ reply</a> + </div> <hr class="thin"> {% endfor %} </div>