aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Spek <p.spek@tyil.nl>2020-03-09 12:48:12 +0100
committerPatrick Spek <p.spek@tyil.nl>2021-08-14 11:59:32 +0200
commitc8123c155b237e6717a500923376918bb0a4c38a (patch)
tree31d494ba02c8a3b476433a8ea189ce586588c359
parent06683b22c139a8ebf637256fad1a79734d872964 (diff)
Add Mutt configuration
-rw-r--r--.config/localmail/accounts/tyil@freedom.nl.yaml18
-rw-r--r--.config/localmail/accounts/tyil@national.shitposting.agency.yaml18
-rw-r--r--.config/localmail/accounts/tyil@scriptkitties.church.yaml18
-rw-r--r--.config/localmail/config.yaml1
-rw-r--r--.config/neomutt/neomuttrc90
-rwxr-xr-x.local/bin/localmail198
-rwxr-xr-x.local/bin/smtp-capture52
-rw-r--r--.local/lib/perl5/App/Localmail.pm54
8 files changed, 449 insertions, 0 deletions
diff --git a/.config/localmail/accounts/tyil@freedom.nl.yaml b/.config/localmail/accounts/tyil@freedom.nl.yaml
new file mode 100644
index 0000000..f51f49f
--- /dev/null
+++ b/.config/localmail/accounts/tyil@freedom.nl.yaml
@@ -0,0 +1,18 @@
+incoming:
+ protocol: imap
+ server: imap.freedom.nl
+ ssl: true
+ username: tyil@freedom.nl
+ password:
+ source: pass
+ file: /home/tyil/.password-store/email/freedom.nl/tyil.gpg
+outgoing:
+ protocol: smtp
+ server: smtp.freedom.nl
+ ssl: true
+ username: tyil@freedom.nl
+ password:
+ source: pass
+ file: /home/tyil/.password-store/email/freedom.nl/tyil.gpg
+ handles:
+ - tyil@freedom.nl
diff --git a/.config/localmail/accounts/tyil@national.shitposting.agency.yaml b/.config/localmail/accounts/tyil@national.shitposting.agency.yaml
new file mode 100644
index 0000000..959ea70
--- /dev/null
+++ b/.config/localmail/accounts/tyil@national.shitposting.agency.yaml
@@ -0,0 +1,18 @@
+incoming:
+ protocol: imap
+ server: mail.cock.li
+ ssl: true
+ username: tyil@national.shitposting.agency
+ password:
+ source: pass
+ file: /home/tyil/.password-store/email/national.shitposting.agency/tyil.gpg
+outgoing:
+ protocol: smtp
+ server: mail.cock.li
+ ssl: true
+ username: tyil@national.shitposting.agency
+ password:
+ source: pass
+ file: /home/tyil/.password-store/email/national.shitposting.agency/tyil.gpg
+ handles:
+ - tyil@national.shitposting.agency
diff --git a/.config/localmail/accounts/tyil@scriptkitties.church.yaml b/.config/localmail/accounts/tyil@scriptkitties.church.yaml
new file mode 100644
index 0000000..c455413
--- /dev/null
+++ b/.config/localmail/accounts/tyil@scriptkitties.church.yaml
@@ -0,0 +1,18 @@
+incoming:
+ protocol: imap
+ server: tyil.email
+ ssl: true
+ username: tyil@scriptkitties.church
+ password:
+ source: pass
+ file: /home/tyil/.password-store/email/scriptkitties.church/tyil.gpg
+outgoing:
+ protocol: smtp
+ server: tyil.email
+ ssl: true
+ username: tyil@scriptkitties.church
+ password:
+ source: pass
+ file: /home/tyil/.password-store/email/scriptkitties.church/tyil.gpg
+ handles:
+ - tyil@scriptkitties.church
diff --git a/.config/localmail/config.yaml b/.config/localmail/config.yaml
new file mode 100644
index 0000000..3fef4af
--- /dev/null
+++ b/.config/localmail/config.yaml
@@ -0,0 +1 @@
+maildir: /home/tyil/mail
diff --git a/.config/neomutt/neomuttrc b/.config/neomutt/neomuttrc
new file mode 100644
index 0000000..76f48b6
--- /dev/null
+++ b/.config/neomutt/neomuttrc
@@ -0,0 +1,90 @@
+# Unbind keys
+bind index,pager a noop
+bind index,pager d noop
+bind index,pager t noop
+bind index,pager \\ noop
+
+# "Global" keys
+bind attach,index,pager \CD next-page
+bind attach,index,pager \CU previous-page
+bind attach,index g first-entry
+bind attach,index G last-entry
+
+macro index,pager t "<modify-labels>"
+macro index,pager \\ "<vfolder-from-query>"
+
+# Sidebar
+set sidebar_visible=yes
+set sidebar_width=10
+
+bind index J sidebar-next
+bind index K sidebar-prev
+bind index <space> sidebar-open
+
+# Email addresses in use
+alternates -group personal p.spek@tyil.nl
+alternates -group personal p.spek@tyil.work
+alternates -group personal tyil@freedom.nl
+
+# Inbox
+set mbox_type=Maildir
+set folder="~/mail"
+set spoolfile=+/
+set sort=threads
+set index_format="%-60.60s %zc %-15.15L %g"
+
+set virtual_spoolfile=yes
+virtual-mailboxes \
+ "Inbox" "notmuch://?query=not tag:archive and not tag:trash"\
+ "Archive" "notmuch://?query=tag:archive"\
+ "Sent" "notmuch://?query=tag:sent"\
+ "Trash" "notmuch://?query=tag:trash"
+
+macro index a "<modify-labels>+archive -unread -inbox<enter>"
+macro index d "<modify-labels>+trash -unread -inbox<enter>"
+
+# Pager
+macro pager a "<modify-labels>+archive -unread -inbox<enter><next-entry>"
+macro pager d "<modify-labels>+trash -unread -inbox<enter><next-entry>"
+
+bind pager G bottom
+bind pager g top
+bind pager j next-line
+bind pager k previous-line
+
+# Composing
+set edit_headers=yes
+set signature="~/documents/email-signature.txt"
+set send_charset="utf-8"
+
+set from="p.spek@tyil.nl"
+set reverse_name=yes
+
+set crypt_autosign=yes
+set pgp_sign_as="0x031D65902E840821"
+set pgp_self_encrypt=yes
+set crypt_opportunistic_encrypt = yes
+
+# Sending mail
+set sendmail="/home/tyil/.local/bin/smtp-capture"
+set copy=no
+set record=""
+
+# PGP
+set pgp_decode_command="gpg --status-fd=2 %?p?--passphrase-fd 0? --no-verbose --quiet --batch --output - %f"
+set pgp_verify_command="gpg --status-fd=2 --no-verbose --quiet --batch --output - --verify %s %f"
+set pgp_decrypt_command="gpg --status-fd=2 %?p?--passphrase-fd 0? --no-verbose --quiet --batch --output - %f"
+set pgp_sign_command="gpg --no-verbose --batch --quiet --output - %?p?--passphrase-fd 0? --armor --detach-sign --textmode %?a?-u %a? %f"
+set pgp_clearsign_command="gpg --no-verbose --batch --quiet --output - %?p?--passphrase-fd 0? --armor --textmode --clearsign %?a?-u %a? %f"
+set pgp_encrypt_only_command="pgpewrap gpg --batch --quiet --no-verbose --output - --encrypt --textmode --armor --always-trust -- -r %r -- %f"
+set pgp_encrypt_sign_command="pgpewrap gpg %?p?--passphrase-fd 0? --batch --quiet --no-verbose --textmode --output - --encrypt --sign %?a?-u %a? --armor --always-trust -- -r %r -- %f"
+set pgp_import_command="gpg --no-verbose --import %f"
+set pgp_export_command="gpg --no-verbose --export --armor %r"
+set pgp_verify_key_command="gpg --verbose --batch --fingerprint --check-sigs %r"
+set pgp_list_pubring_command="gpg --no-verbose --batch --quiet --with-colons --with-fingerprint --with-fingerprint --list-keys %r"
+set pgp_list_secring_command="gpg --no-verbose --batch --quiet --with-colons --with-fingerprint --with-fingerprint --list-secret-keys %r"
+set pgp_good_sign="^\\[GNUPG:\\] GOODSIG"
+set pgp_check_gpg_decrypt_status_fd
+
+# "Theme"
+color index default default '.*'
diff --git a/.local/bin/localmail b/.local/bin/localmail
new file mode 100755
index 0000000..dc1092a
--- /dev/null
+++ b/.local/bin/localmail
@@ -0,0 +1,198 @@
+#!/usr/bin/env perl
+
+use v5.16;
+use feature qw/say signatures/;
+use strict;
+use utf8;
+use warnings;
+
+use Data::UUID;
+use Email::Simple;
+use File::Copy;
+use File::Slurp;
+use Net::IMAP::Simple;
+use Net::SMTP;
+use File::Path;
+use File::Basename;
+
+use Data::Dumper;
+
+use App::Localmail;
+
+sub main (@args) {
+ my $action = shift @args;
+
+ return 1 unless defined $action;
+
+ my %actions = (
+ fetch => \&fetch,
+ send => \&send,
+ );
+
+ return 2 unless exists $actions{$action};
+
+ return $actions{$action}(App::Localmail::base_config(), @args);
+}
+
+sub fetch ($config, @args) {
+ # Get all passwords
+ App::Localmail::config_passwords($config);
+
+ # Fetch email for each account
+ my $uuid = Data::UUID->new;
+ my $maildir = $config->{localmail}{maildir};
+
+ for my $account (keys %{$config->{accounts}}) {
+ my $current = $config->{accounts}{$account}{incoming};
+
+ if (!defined $current->{password}{plain}) {
+ say "No password for '$account'";
+ next;
+ }
+
+ say "Fetching mail for $account";
+ say " Connecting to $current->{server}";
+
+ my $connection = Net::IMAP::Simple->new(
+ $current->{server},
+ use_ssl => $current->{ssl} // 1,
+ );
+
+ if (!$connection) {
+ say " Failed: ". $Net::IMAP::Simple::errstr."\n";
+ next;
+ }
+
+ if ($current->{starttls}) {
+ say ' Applying StartTLS';
+ $connection->starttls;
+ }
+
+ say " Authenticating";
+ if (!$connection->login($current->{username}, $current->{password}{plain})) {
+ say ' Failed: '.$connection->errstr."\n";
+ next;
+ }
+
+ say " Fetching mailboxes";
+ for my $mbox ($connection->mailboxes) {
+ $connection->select($mbox);
+
+ my @messages = keys(%{$connection->list});
+ my $count = 0;
+
+ say " $mbox (".($#messages + 1).")";
+
+ for my $message (@messages) {
+ $count++;
+ my $current_uuid = fc($uuid->to_string($uuid->create));
+
+ say " $current_uuid ($count)";
+
+ open(FH, '>', "$maildir/tmp/$current_uuid.eml") or die $!;
+ print FH $connection->fetch($message);
+ close(FH);
+
+ move("$maildir/tmp/$current_uuid.eml", "$maildir/new/$current_uuid.eml");
+ $connection->delete($message);
+ }
+
+ $connection->close;
+ }
+
+ say " Closing connection";
+ $connection->quit;
+ }
+
+ return 0;
+}
+
+sub send ($config, @args) {
+ # Get all passwords
+ App::Localmail::config_passwords($config);
+
+ my $uuid = Data::UUID->new;
+ my $maildir = $config->{localmail}{maildir};
+
+ # Create a hash of sender addresses and related accounts
+ my %senders;
+
+ for my $account (keys %{$config->{accounts}}) {
+ for my $handler (@{$config->{accounts}{$account}{outgoing}{handles}}) {
+ $senders{$handler} = $account;
+ }
+ }
+
+ # Walk through the queue of emails to send
+ for my $item (glob("$maildir/queue/*")) {
+ next unless -d $item;
+ next unless -f "$item/message.eml";
+
+ my ($id, $path) = File::Basename::fileparse($item);
+
+ say "Sending $id";
+
+ my $body = File::Slurp::read_file("$item/message.eml");
+ my $email = Email::Simple->new($body);
+ my $from = $email->header("From");
+ my @recipients = File::Slurp::read_file("$item/recipients");
+
+ if (!exists $senders{$from}) {
+ say " No account handles mail from '$from'";
+ next;
+ }
+
+ my $current = $config->{accounts}{$senders{$from}}{outgoing};
+
+ say " Connecting to ".$current->{server};
+
+ # Send the email
+ my $connection = Net::SMTP->new(
+ $current->{server},
+ SSL => $current->{ssl},
+ Timeout => $current->{timeout} // 5,
+ );
+
+ say " Authenticating";
+
+ if (!$connection->auth($current->{username}, $current->{password}{plain})) {
+ say " Failed: ".$connection->message;
+ next;
+ }
+
+ say " MAIL FROM";
+ if (!$connection->mail($from)) {
+ say " Failed: ".$connection->message;
+ next;
+ }
+
+ say " RCPT TO";
+ if (!$connection->recipient(@recipients)) {
+ say " Failed: ".$connection->message;
+ next;
+ }
+
+ say " DATA";
+ if (!$connection->data($body)) {
+ say " Failed: ".$connection->message;
+ next;
+ }
+
+ $connection->quit;
+
+ say " Sent!";
+
+ if (open(FH, '>', "$maildir/sent/$id.eml")) {
+ say " Moving to sentdir";
+
+ print FH $email->as_string;
+ close(FH);
+
+ File::Path::rmtree($item);
+ }
+ }
+
+ return 0;
+}
+
+exit main(@ARGV);
diff --git a/.local/bin/smtp-capture b/.local/bin/smtp-capture
new file mode 100755
index 0000000..bd31cb3
--- /dev/null
+++ b/.local/bin/smtp-capture
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+
+main()
+{
+ # Handle opts
+ while getopts ":h" opt
+ do
+ case "$opt" in
+ h) usage && exit 0 ;;
+ *)
+ printf "Invalid option passed: %s\n" "$OPTARG" >&2
+ ;;
+ esac
+ done
+
+ shift $(( OPTIND - 1 ))
+
+ queuedir="$HOME/mail/queue/$(uuidgen)"
+ mkdir -p -- "$queuedir"
+ cat > "$queuedir/message.eml"
+
+ for i in "$@"
+ do
+ printf "$i\n" >> "$queuedir/recipients"
+ done
+}
+
+usage()
+{
+ cat <<EOF
+Usage:
+ ${0##*/} -h
+
+Capture email ment to be send through an SMTP client. This allows you to queue
+them up easily.
+
+Options:
+ -h Show this help text and exit.
+EOF
+}
+
+main "$@"
diff --git a/.local/lib/perl5/App/Localmail.pm b/.local/lib/perl5/App/Localmail.pm
new file mode 100644
index 0000000..db39fae
--- /dev/null
+++ b/.local/lib/perl5/App/Localmail.pm
@@ -0,0 +1,54 @@
+#!/usr/bin/env false
+
+use v5.20;
+use feature qw/say signatures/;
+use strict;
+use utf8;
+use warnings;
+
+use YAML::XS;
+use File::Basename;
+use File::Slurp;
+
+package App::Localmail;
+
+sub base_config () {
+ my $config_dir = "$ENV{HOME}/.config/localmail";
+ my $config = {};
+
+ # Load main configuration
+ $config->{localmail} = YAML::XS::Load(File::Slurp::read_file("$config_dir/config.yaml"));
+
+ # Load account configurations
+ for (glob("$config_dir/accounts/*.yaml")) {
+ my ($name, $path, $suffix) = File::Basename::fileparse($_, ('.yaml'));
+ my $yaml = File::Slurp::read_file($_);
+
+ $config->{accounts}->{$name} = YAML::XS::Load($yaml);
+ }
+
+ $config->{localmail}{maildir} //= "$ENV{HOME}/.maildir";
+
+ $config;
+}
+
+sub config_passwords ($config) {
+ # Get passwords where necessary
+ for (keys %{$config->{accounts}}) {
+ if (!defined($config->{accounts}{$_}{incoming}{password}{plain})) {
+ my $file = $config->{accounts}{$_}{incoming}{password}{file};
+ chomp (my $password = qx/gpg -d "$file" | head -n 1/);
+
+ $config->{accounts}{$_}{incoming}{password}{plain} = $password;
+ }
+
+ if (!defined($config->{accounts}{$_}{outgoing}{password}{plain})) {
+ my $file = $config->{accounts}{$_}{outgoing}{password}{file};
+ chomp (my $password = qx/gpg -d "$file" | head -n 1/);
+
+ $config->{accounts}{$_}{outgoing}{password}{plain} = $password;
+ }
+ }
+}
+
+1;