aboutsummaryrefslogtreecommitdiffhomepage
path: root/bin/mail/deliver.sh
blob: abe582329f6c7a96d5446ae7c7485725e1a2edbd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#! /bin/bash

# Deliver incoming mail to proper mailbox
# TODO image/audio mail part
# TODO CJK Subject in index/pager mode: tofo or backslash

epoch=$(date +%s)
mail_date="$(date --rfc-email -d @${epoch})"

# shell opt/trap {{{
shopt -s nocasematch extglob

# update index for dovecot
trap 'doveadm force-resync ${mailbox:-/}' EXIT

# temp file for decodemail (GNU Mailutils)
tmp_mailbox=$(mktemp -d); mkdir -p ${tmp_mailbox}/{tmp,new,cur}
cat >${tmp_mailbox}/cur/mail
trap 'rm -rf ${tmp_mailbox}' EXIT
# }}}
# log each delivery {{{
log=~/Maildir/cur/deliver.log.${epoch}
trap 'doveadm force-resync /' EXIT

# add a new log file, or reuse existing log file
outdated_log=$(grep -rlE 'From:\s+<?MDA' ~/Maildir/cur | head -1)
if [ -z "$outdated_log" ]; then
  <<-HEADER cat >${log}
	From: MDA <pham@topo.tw>
	Date: ${mail_date}
	Message-ID: <$log>
	Content-Type: text/plain; charset=UTF-8
	Subject: Delivery Log

	HEADER
else
  mv "$outdated_log" $log
  sed -i "1,/^$/ {s#^Date: .*#Date: ${mail_date}#; s#^Message-ID: .*#Message-ID: <${log}>#}" $log
fi

# Set stderr after process $log properly
exec 2>>$log
# }}}
# vars about message {{{
MAIL="$(decodemail ${tmp_mailbox})"
# TODO process multi-line header field
header="$(<<<"$MAIL" sed '/^$/ q; /^[[:blank:]]/ d;')"
body="$(<<<"$MAIL" sed -n '/^$/,$ p' | sed '1d')"

# vars about output
iso_date=$(date --iso=seconds -d @${epoch})
maildir=${HOME}/Maildir
mailbox=
# }}}
# FUNCTION: Set set_stdout {{{
set_stdout() {
  filename=${Subject// /_}
  path=${maildir}/${mailbox}${mailbox:+/}new/${iso_date//:/}.${filename//[^[:alnum:]_]/}
  mkdir -p $(dirname $path)

  exec 1>$path
}
# }}}
# FUNCTION: print mail {{{
print_mail() {
  if [ "$private" = true ]; then
    <<-MAIL cat
		Date: ${mail_date}
		Message-ID: ${Message_ID}
		Content-Type: text/plain; charset=UTF-8
		Self: true
		Subject: ${heading}

		$(sed 1d <<<"$body")
	MAIL
  else
    echo "$MAIL"
  fi
}
# }}}
# FUNCTION: save as private message {{{
private_message() {
  heading="$(head -1 <<<"${body}")"

  if [[ "${heading}" =~ ^"." ]]; then
    mailbox=act
    heading=${heading#.}
  else
    mailbox=box
  fi

  private=true
}
# }}}

# save each header field into vars {{{
# TODO Use GNU MailUtils to save header
while read line; do
  [[ "${line}" =~ ^" "|^"	" ]] && ${field}+=" ${line##*( )}" && continue

  IFS=': ' read field value <<<"${line}"
  field="${field^^}"
  field="${field//-/_}"
  declare ${field}="${value}"
done <<<"$header"
# }}}
# decide mailbox by vars {{{
if [[ "$SENDER" = pham@topo.tw && -n $CHAT_VERSION ]]; then
  private_message
elif [[ "${FROM}" =~ riverbien ]]; then
  mailbox=river
elif [[ "${FROM}" =~ MAILER-DAEMON|accounts ]]; then
  mailbox=
elif [[ "${FROM}" =~ taiwandreamer|imtaiwanese18741130|recall ]]; then
  mailbox=recall
elif [[ "${TO}" =~ '+'|'=' ]]; then
  mailbox=${TO#*[+=]}       # remove chars before symbol of mailbox
  mailbox=${mailbox%@*}     # remove suffix for mail address
elif [[ "${FROM}${RETURN_PATH}" =~ notifications@github.com|noreply@github.com ]]; then
  mailbox=zd/github
elif [[ "${FROM}" =~ jgbsmart.com ]]; then
  mailbox=rent
elif [[ "${SUBJECT}" =~ 帳單|轉帳|對帳|付款|發票|消費|繳費|收據|費用|簽帳|Invoice|Billing ]]; then
  mailbox=pay
elif [[ "${TO}" =~ dmarc@topo.tw ]]; then
  mailbox=zd/dmarc
elif [[ "${LIST_ID}" =~ ^'Open Street Map Taiwan' ]]; then
  mailbox=FOSS/osm
elif [[ "${TO}" =~ talk-ja@openstreetmap.org ]]; then
  mailbox=zl/talk-ja
elif [[ "${LIST_ID}" =~ rjarry/aerc-discuss ]]; then
  mailbox=zl/aerc
elif [[ "${LIST_ID}" =~ mutt-users.mutt.org ]]; then
  mailbox=zl/mutt
elif [[ "${LIST_ID}" =~ archlinux.org ]]; then
  mailbox=zl/arch
elif [[ "${SUBJECT}" =~ 啟用 ]]; then
  mailbox=service
elif [[
  "${SUBJECT}" =~  電子報|快訊|newsletter ||
  "${FROM}${TO}" =~ substack|service@kucw.io|linuxhandbook
  ]]; then
  mailbox=news
elif [[ "${SUBJECT}" =~ 密碼|安全性警示|登入|存取|驗證|確認|login|verif|sign-in ]]; then
  mailbox=login
elif [[ "${TO}" = cloudflare@topo.tw ]]; then
  mailbox=SRV/cloudflare
elif [[
  "${SUBJECT}" =~ 通知|提及|未讀|更新|核對|嘟文|unread|summary|mention|introduc  ||
  "${FROM}" =~ iservice@narlabs.org.tw ||
  "${FROM}" =~ notification[s]?@|no-reply@hackmd.io
  ]]; then
  mailbox=update
elif [[
  "${SUBJECT}${FROM}" =~ 優惠|快訊|願望清單|期待|活動|eDM|invitation ||
  ${FROM} =~ cora.computer|noreply@steampowered.com ||
  -n "${LIST_ID}${LIST_UNSUBSCRIBE}${FEEDBACK_ID}${THREAD_INDEX}${X_MAILGUN_TAG}${X_SFMC_STACK}"
  ]]; then
  mailbox=promote
fi
# }}}

# deliver mail to mailbox
set_stdout && print_mail

# log to stderr
declare -i width_mailbox=$(wc -c <<<"${mailbox:-INBOX}")
spaces="$(printf %$(( 16 - ${width_mailbox} ))s)"
echo -e $(date '+%m/%d %H:%M' -d @${epoch}) "=> ${mailbox:-INBOX}" "$spaces" "${heading:-${SUBJECT}}" >&2

# vim:fdm=marker fdl=0