crabmail

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

commit 5f7c757c00d66c56a5f033062de466a964cd2e4f
parent a32203d4444e1322724521cf4bad55913dc22085
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Sun, 12 Dec 2021 23:01:03 -0800

major style improvements

Diffstat:
Mcrabmail/src/filters.rs | 12------------
Mcrabmail/src/main.rs | 9+++++----
Mcrabmail/templates/base.html | 4+++-
Mcrabmail/templates/static/style.css | 31++++++++++++++++++++++++++++++-
Mcrabmail/templates/thread.html | 13++++++++-----
Mcrabmail/templates/threadlist.html | 16+++++++++-------
6 files changed, 55 insertions(+), 30 deletions(-)

diff --git a/crabmail/src/filters.rs b/crabmail/src/filters.rs @@ -39,15 +39,3 @@ fn timeago(unixtime: u64) -> String { _ => format!("{} {}s ago", amount, metric), } } -pub fn get_body(email: &&ParsedMail) -> askama::Result<String> { - let core_email = email.subparts.get(0).unwrap_or(email); - - #[cfg(feature = "html")] - {} - - if core_email.ctype.mimetype == "text/plain" { - // TODO html escape this. - return Ok(core_email.get_body().unwrap_or("".to_string())); - } - return Ok(String::from("[No valid body found]")); -} diff --git a/crabmail/src/main.rs b/crabmail/src/main.rs @@ -1,12 +1,11 @@ use anyhow::{anyhow, Context, Result}; use askama::Template; -use mailparse::{dateparse, parse_headers, parse_mail, MailHeaderMap, ParsedMail}; +use mailparse::*; use mbox_reader::MboxFile; use std::collections::HashMap; use std::fmt; use std::fs::{File, OpenOptions}; use std::io::prelude::*; -use urlencoding::encode; mod filters; @@ -25,7 +24,7 @@ Usage: crabmail struct Email { // TODO allocs id: String, - from: String, + from: SingleInfo, subject: String, in_reply_to: Option<String>, date: u64, // unix epoch. received date @@ -91,7 +90,9 @@ fn local_parse_email(data: &[u8]) -> Result<Email> { .get_first_value("received") .unwrap_or(headers.get_first_value("date").context("No date header")?), )? as u64; - let from = headers.get_first_value("from").context("No from header")?; + let from = addrparse_header(headers.get_first_header("from").context("No from header")?)? + .extract_single_info() + .context("Could not parse from header")?; return Ok(Email { id, diff --git a/crabmail/templates/base.html b/crabmail/templates/base.html @@ -3,7 +3,7 @@ <head> <meta charset="utf-8"> <meta http-equiv="Permissions-Policy" content="interest-cohort=()"/> - <link rel="stylesheet" type="text/css" href="/style.css" /> + <link rel="stylesheet" type="text/css" href="../style.css" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=0" /> <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📧</text></svg>"> <meta name="description" content="Crabmail mailing list"> @@ -11,6 +11,7 @@ {% block head %}{% endblock %} </head> <body> + <main> <div id="content"> {% block content %}{% endblock %} </div> @@ -18,5 +19,6 @@ <div class="footer"> Archive generated with <a href="https://git.alexwennerberg.com/crabmail/">crabmail</a> </div> + </main> </body> </html> diff --git a/crabmail/templates/static/style.css b/crabmail/templates/static/style.css @@ -3,9 +3,11 @@ body { padding-left: 4ch; padding-right: 4ch; margin: auto; - font-family: "Archivo", Helvetica, Arial, Sans-serif; + font-family: "Roboto", Helvetica, Arial, Sans-serif; word-wrap: break-word; line-height: 1.5; + max-width: 79ch; + padding: 1ch; } body > hr { margin-left: -1ch; } @@ -16,6 +18,22 @@ table { border-spacing: 0.5em 0.1em; } font-family: "Roboto Mono", monospace; } +.message-sum { + margin: 4px; +} +.addr { + color: darkblue; +} + +.threadlink { + font-size: 1.2rem; + font-weight: bold; +} + +.timeago { + font-style: italic; + color: grey; +} .email-body { white-space:pre-line; @@ -37,6 +55,7 @@ table { border-spacing: 0.5em 0.1em; } hr.thin { border: 0; height: 0; + color: lightgrey; border-top: 1px solid; } @@ -67,6 +86,16 @@ table td { padding: 0 0.1em; } +a { + text-decoration: none; +} + +a:visited { + color: blue; +} +a:hover{ + text-decoration: underline; +} table.core { width: 100%; border-collapse: collapse; diff --git a/crabmail/templates/thread.html b/crabmail/templates/thread.html @@ -2,15 +2,18 @@ {% block content %} <div class="page-title"><h1>{{root.subject}}</h1></div> +<hr class="thin"> <div> {% for message in messages %} - <div class="message"> - <h3 id="{{message.id}}"><a href="#{{message.id}}">#</a> {{message.subject}}</h3> - <b>From: </b>{{message.from}} <em>{{message.date | time_ago}}</em><br> - <div class="email-body"> + <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="#{{message.id}}">🔗</a> + <div class="email-body"> {{message.body}} </div> - <hr> + <hr class="thin"> {% endfor %} </div> </div> diff --git a/crabmail/templates/threadlist.html b/crabmail/templates/threadlist.html @@ -2,14 +2,16 @@ {% block content %} <div class="page-title"><h1>Crabmail Mailing List</h1></div> - <div> - <table> {% for message in messages %} - <tr> - <td><a href="threads/{{message.date}}.html">{{message.subject}}</a></td> - <td> {{message.from}}</td> - <td>{{message.date | time_ago}}</td> + <div class="message-sum"> + <a href="threads/{{message.date}}.html" class="threadlink">{{message.subject}}</a> + <br> + <a href="mailto:{{message.from.addr}}" class="addr">{%match message.from.display_name %} + {% when Some with (name) %} + {{name}}{% when none %}{{message.from.addr}}{% endmatch %}</a> +<span class="timeago">{{message.date | time_ago}}</span> + <br> + </div> {% endfor %} - </table> </div> {% endblock %}