This commit is contained in:
nervuri 2023-08-11 10:28:39 +00:00
commit dcebb8fdc4
9 changed files with 455 additions and 0 deletions

21
LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 nervuri
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

23
README.md Normal file
View File

@ -0,0 +1,23 @@
# E-mail configs
This repo contains my configs for mutt, mpop, msmtp and [a bespoke mail filtering script](mail-filter.user.py).
It also contains a sample getmail config for IMAP accounts, which downloads all messages and deletes them from the server.
## Notes
In recent versions of Mutt, you can use `local_date_header = no` to hide your timezone. If you're running a version prior to 2.2.0, you can achieve the same result using a shell alias: `alias mutt='TZ=UTC mutt'`.
Also in recent versions of Mutt, the User-Agent header is [disabled by default](https://gitlab.com/muttmua/mutt/-/commit/82973a6ea99075b822d338c63639787bf2445a41).
My muttrc has basic Vim key bindings, but if you want to go further in that direction see [Mutt, the Vim Way](https://www.ryanlue.com/posts/2017-05-21-mutt-the-vim-way).
In mpop and msmtp I've pinned the Let's Encrypt root certificate using `tls_trust_file`. If you want to pin the end-entity cert, use the `tls_fingerprint` variable. You can obtain a server's TLS fingerprint by running:
```
openssl s_client $HOST:$PORT </dev/null 2>/dev/null | openssl x509 -fingerprint -sha256 -enddate -noout
```
Run it with and without `torsocks` to check from multiple network perspectives.
mpop and msmtp are configured to fetch mail account passwords by calling [pass](https://www.passwordstore.org/). You could also use a variant of `pass` called [passage](https://github.com/FiloSottile/passage) that uses `age` instead of GPG.

22
getmail/getmail.conf Normal file
View File

@ -0,0 +1,22 @@
# https://getmail6.org/configuration.html
[retriever]
type = SimpleIMAPSSLRetriever
server = imap.mail.yahoo.com
port = 993
mailboxes = ALL
username = USER@yahoo.com
#password = PASSWORD # or, rather:
password_command = ("pass", "YAHOO_ACCOUNT")
[destination]
type = Maildir
path = ~/Mail/USER/
[options]
delete = true
message_log = ~/Mail/USER.log
# do not alter messages
delivered_to = false
received = false

61
mail-filter.user.py Executable file
View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
'Simple e-mail filter'
# This script could be shorter, but using BytesFeedParser and only
# parsing the headers makes it significantly more efficient
# when handling messages with large attachments.
from email.parser import BytesFeedParser
from email.policy import default
from pathlib import Path
from secrets import token_hex
from time import time
import sys
import os
basedir = '~/Mail/USER'
BUFSIZE = 8192 # io.DEFAULT_BUFFER_SIZE
buf = b''
# Parse headers.
parser = BytesFeedParser(policy=default)
parsed_part = b''
separators = [b'\n\n', b'\r\n\r\n']
while True:
buf = sys.stdin.buffer.read(BUFSIZE)
parsed_part += buf
parser.feed(buf)
if any([s in buf for s in separators]) or not buf:
break
headers = parser.close()
# Choose destination directory based on e-mail headers.
ddir = 'Inbox'
sender = headers.get('sender', '')
if 'taler-bounces' in sender and '@gnu.org' in sender:
# GNU Taler mailing list
ddir = 'taler'
elif 'community-bounces@freecalypso.org' in sender:
# FreeCalypso mailing list
ddir = 'freecalypso'
# Generate filename.
rand = str(time()) + '.' + token_hex(4)
file = f'{basedir}/{ddir}/new/{rand}'
file_full_path = str(Path(file).expanduser())
# Write message to file.
with open(file_full_path, 'wb') as f:
f.write(parsed_part)
while True:
buf = sys.stdin.buffer.read(BUFSIZE)
if not buf:
break
f.write(buf)
# Output file name and size.
size_kb = round(os.path.getsize(file_full_path) / 1024, 1)
print(file + ' - ' + str(size_kb) + ' KB')

38
mpop/config Normal file
View File

@ -0,0 +1,38 @@
# https://marlam.de/mpop/mpop.html
# Set default values for all following accounts.
defaults
tls on
tls_starttls off
# TLSv1.3 only
# https://gnutls.org/manual/html_node/Priority-Strings.html
tls_priorities PFS:-VERS-ALL:+VERS-TLS1.3
# Tor
proxy_host 127.0.0.1
proxy_port 9050
auth on
received_header off
# Deliver mail:
#delivery maildir ~/Mail/USER/Inbox
#delivery mda "/usr/bin/fdm -f $XDG_CONFIG_HOME/fdm.conf -v fetch"
delivery mda "$HOME/scripts/mail-filter.user.py"
### Disroot ###
account user_disroot
host disroot.org
port 995
tls_trust_file /etc/ssl/certs/ISRG_Root_X1.pem
#tls_fingerprint AD:87:AC:96:F8:DC:6E:1F:2E:0B:C5:6D:79:43:34:25:D8:2D:8F:02:74:69:7F:F3:AD:8D:26:73:9B:BF:3F:45
# expires: Sep 21 16:25:17 2023 GMT
# openssl s_client disroot.org:995 </dev/null 2>/dev/null | openssl x509 -fingerprint -sha256 -enddate -noout
user USER
passwordeval pass show USER-disroot
account default : user_disroot

41
msmtp/config Normal file
View File

@ -0,0 +1,41 @@
# https://marlam.de/msmtp/msmtp.html
# NOTE: Debian's msmtp AppArmor profile restricts using this file as a symlink,
# so GNU Stow won't work. Use a hardlink.
# Set default values for all following accounts.
defaults
#logfile $XDG_CACHE_HOME/msmtp.log
logfile - # log to stdout
tls on
tls_starttls off
# TLSv1.3 only
# https://gnutls.org/manual/html_node/Priority-Strings.html
tls_priorities PFS:-VERS-ALL:+VERS-TLS1.3
# Tor
proxy_host 127.0.0.1
proxy_port 9050
auth on
set_date_header off
### Disroot ###
account user_disroot
host disroot.org
port 465
tls_trust_file /etc/ssl/certs/ISRG_Root_X1.pem
#tls_fingerprint AD:87:AC:96:F8:DC:6E:1F:2E:0B:C5:6D:79:43:34:25:D8:2D:8F:02:74:69:7F:F3:AD:8D:26:73:9B:BF:3F:45
# expires: Sep 21 16:25:17 2023 GMT
# openssl s_client disroot.org:465 </dev/null 2>/dev/null | openssl x509 -fingerprint -sha256 -enddate -noout
user USER
passwordeval pass show USER-disroot
from USER@disroot.org
account default : user_disroot

1
mutt/aliases Normal file
View File

@ -0,0 +1 @@
alias example User <USER@example.org>

View File

@ -0,0 +1,122 @@
# https://github.com/shuber2/mutt-gruvbox
# gruvbox dark (contrast dark):
# bg0 = 234
# bg1 = 237
# bg2 = 239
# bg3 = 241
# bg4 = 243
#
# gray = 245
#
# fg0 = 229
# fg1 = 223
# fg2 = 250
# fg3 = 248
# fg4 = 246
#
# red = 167
# green = 142
# yellow = 214
# blue = 109
# purple = 175
# aqua = 108
# orange = 208
# See http://www.mutt.org/doc/manual/#color
color attachment color109 color16
color bold color229 color16
color error color167 color16
color hdrdefault color246 color16
color indicator color223 color237
color markers color243 color16
color normal color223 color16
color quoted color250 color16
color quoted1 color108 color16
color quoted2 color250 color16
color quoted3 color108 color16
color quoted4 color250 color16
color quoted5 color108 color16
color search color16 color208
color signature color108 color16
color status color15 color16
color tilde color243 color16
color tree color142 color16
color underline color223 color239
color sidebar_divider color250 color16
color sidebar_new color142 color16
color index color142 color16 ~N
color index color108 color16 ~O
color index color109 color16 ~P
color index color214 color16 ~F
color index color175 color16 ~Q
color index color167 color16 ~=
color index color16 color223 ~T
color index color16 color167 ~D
color header color214 color16 "^(To:|From:)"
color header color142 color16 "^Subject:"
color header color108 color16 "^X-Spam-Status:"
color header color108 color16 "^Received:"
# Regex magic for URLs and hostnames
#
# Attention: BSD's regex has RE_DUP_MAX set to 255.
#
# Examples:
# http://some-service.example.com
# example.com
# a.example.com
# some-service.example.com
# example.com/
# example.com/datenschutz
# file:///tmp/foo
#
# Non-examples:
# 1.1.1900
# 14.02.2022/24:00
# 23.59
# w.l.o.g
# team.its
color body color142 color16 "[a-z]{3,255}://[[:graph:]]*"
color body color142 color16 "([-[:alnum:]]+\\.)+([0-9]{1,3}|[-[:alpha:]]+)/[[:graph:]]*"
color body color142 color16 "([-[:alnum:]]+\\.){2,255}[-[:alpha:]]{2,10}"
# IPv4 and IPv6 stolen from https://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
#color body color142 color16 "((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"
#color body color142 color16 "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"
# Mail addresses and mailto URLs
color body color208 color16 "[-a-z_0-9.%$]+@[-a-z_0-9.]+\\.[-a-z][-a-z]+"
color body color208 color16 "mailto:[-a-z_0-9.]+@[-a-z_0-9.]+"
## some simleys and stuff
#color body color16 color214 "[;:]-*[)>(<lt;|]"
color body color229 color16 "\\*[- A-Za-z]+\\*"
color body color214 color16 "^-.*PGP.*-*"
color body color142 color16 "^gpg: Good signature from"
color body color167 color16 "^gpg: Can't.*$"
color body color214 color16 "^gpg: WARNING:.*$"
color body color167 color16 "^gpg: BAD signature from"
color body color167 color16 "^gpg: Note: This key has expired!"
color body color214 color16 "^gpg: There is no indication that the signature belongs to the owner."
color body color214 color16 "^gpg: can't handle these multiple signatures"
color body color214 color16 "^gpg: signature verification suppressed"
color body color214 color16 "^gpg: invalid node with packet of type"
color body color142 color16 "^Good signature from:"
color body color167 color16 "^.?BAD.? signature from:"
color body color142 color16 "^Verification successful"
color body color167 color16 "^Verification [^s][^[:space:]]*$"
color compose header color223 color16
color compose security_encrypt color175 color16
color compose security_sign color109 color16
color compose security_both color142 color16
color compose security_none color208 color16

126
mutt/muttrc Normal file
View File

@ -0,0 +1,126 @@
# http://www.mutt.org/doc/manual/
# Color theme
source ~/.config/mutt/colors-gruvbox-shuber.muttrc
# Send
# https://marlam.de/msmtp/msmtp.html#Using-msmtp-with-Mutt
set sendmail = msmtp
set use_from = yes
set realname = User
set from = USER@example.net
set use_envelope_from = yes
# Multiple accounts
alternates "(^USER@example\.net$)|(^USER@disroot\.org$)"
set reverse_name
# Receive
set folder = ~/Mail/USER/
set mbox_type = Maildir
# Folders
set spoolfile = +Inbox
set postponed = +Drafts
set record = +Sent
set trash = +Trash
mailboxes +Inbox +taler +freecalypso +Drafts +Sent +Trash
# Contacts
set alias_file = "~/.config/mutt/aliases"
set sort_alias = unsorted
set reverse_alias = yes
source $alias_file
# Render HTML in w3m
auto_view text/html
alternative_order text/plain text/html
# Privacy
set user_agent = no
set local_date_header = no # hide timezone
# Other
#set sort = 'threads'
set sort = reverse-last-date-received
set sort_aux = reverse-last-date-received
set include = yes
set fast_reply = yes
set editor = 'nvim "+set textwidth=72 fo+=t"'
#set editor = 'nvim "+set textwidth=72 fo+=w"' # for format=flowed
#set indent_string = '> ' # doesn't work if text_flowed = yes
#set text_flowed = yes # https://incenp.org/notes/2020/format-flowed-neomutt-vim.html
set reflow_text = yes
set reflow_space_quotes = no
#set reflow_wrap = 78
set wrap = 80
set markers = no
set send_charset = 'us-ascii:utf-8'
#set edit_headers = yes
set date_format = "!%a, %Y-%m-%d"
#set date_format = "!%a, %Y-%m-%d at %H:%M %Z"
#set attribution = "On %d, %n wrote:"
set index_format = "%Z %{%a %Y-%m-%d} %-25.25L (%?l?%4l&%4c?) %s"
#set index_format = "%4C %Z %{%b %d} %-15.15L (%?l?%4l&%4c?) %s" # default
# Prevent scroll wheel from going to the next message
bind pager <up> previous-line
bind pager <down> next-line
set pager_stop = yes
## Sidebar
set sidebar_visible = yes
set sidebar_width = 15
set sidebar_next_new_wrap = yes
bind index,pager B sidebar-toggle-visible
bind index,pager K sidebar-prev
bind index,pager J sidebar-next
bind index,pager L sidebar-open
bind index,pager O sidebar-open
bind index,pager \Cp sidebar-prev-new
bind index,pager \Cn sidebar-next-new
# Key bindings
bind index,pager,browser d noop
bind index D delete-message
bind index l display-message
bind browser l select-entry
bind pager l view-attachments
#bind attach l view-mailcap
bind index / limit
bind index h noop
bind pager,attach h exit
#bind browser h goto-parent
macro browser h '<change-dir><kill-line>..<enter>' "Go to parent folder"
bind index G last-entry
bind index gg first-entry
macro index,pager c "<change-folder>?<toggle-mailboxes>" "open a different folder"
macro index C "<copy-message>?<toggle-mailboxes>" "copy a message to a mailbox"
macro index M "<save-message>?<toggle-mailboxes>" "move a message to a mailbox"
macro compose A "<attach-message>?<toggle-mailboxes>" "attach message(s) to this message"
macro index G "|mpop -a\n"
# Key bindings for multiple accounts
# https://feeding.cloud.geek.nz/posts/handling-multiple-identitiesaccounts-in/
# https://unix.stackexchange.com/questions/33458/how-to-easily-set-up-multiple-accounts-in-mutt
macro compose f "<edit-from><kill-line>user<tab><search><enter>"
# PGP
set pgp_default_key = "USER@example.net"
#set crypt_opportunistic_encrypt = yes
#set crypt_autosign = yes
set crypt_replysign = yes
set crypt_replysignencrypted = yes
# Mask subject (it will appear as "..." from the outside)
set crypt_protected_headers_write = yes
# When opening a message with masked subject, save real subject in header cache.
set crypt_protected_headers_save = yes
# Save PGP-encrypted emails as plain text in the "Sent" folder
set fcc_clear = yes
# Save PGP-encrypted emails as encrypted-to-self in the "Sent" folder
#set pgp_self_encrypt = yes
# Change settings based upon message recipients
# Default
#send-hook . 'unset pgp_autosign; unset pgp_autoencrypt'
# ~t = To
#send-hook '~t user@example.org' 'set pgp_autosign; set pgp_autoencrypt'