Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
annotate sbin/bsmtp2dma @ 438:9c3b1966ba91
Extend copyright to 2024
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Wed, 01 May 2024 21:35:43 +0200 |
| parents | 84d2735fe7f6 |
| children | 62cd970aea9c |
| rev | line source |
|---|---|
| 110 | 1 #!/bin/sh |
| 2 # -*- indent-tabs-mode: nil; -*- | |
| 3 : 'A simple replacement for Bacula `bsmtp` when the underlying mailer does | |
| 4 not listen on TCP ports (e.g. `dma`, `ssmtp` et al.). | |
| 5 | |
| 6 :Author: Franz Glasner | |
|
438
9c3b1966ba91
Extend copyright to 2024
Franz Glasner <fzglas.hg@dom66.de>
parents:
386
diff
changeset
|
7 :Copyright: (c) 2019-2024 Franz Glasner. |
| 110 | 8 All rights reserved. |
| 9 :License: BSD 3-Clause "New" or "Revised" License. | |
| 10 See LICENSE for details. | |
| 11 If you cannot find LICENSE see | |
| 12 <https://opensource.org/licenses/BSD-3-Clause> | |
|
386
84d2735fe7f6
Simplified version tagging a lot: it is also faster now.
Franz Glasner <fzglas.hg@dom66.de>
parents:
317
diff
changeset
|
13 :ID: @(#)@@SIMPLEVERSIONTAG@@ |
| 110 | 14 |
| 15 ' | |
| 16 | |
| 17 VERSION="@@VERSION@@" | |
| 18 | |
| 19 USAGE=' | |
| 20 USAGE: bsmtp2dma [OPTIONS] RECIPIENT ... | |
| 21 | |
| 22 Options: | |
| 23 | |
| 111 | 24 -V Show the program version and usage and exit. |
| 25 | |
| 110 | 26 -8 Does nothing. Just a compatibility option for `bsmtp`. |
| 27 | |
|
316
dc3ac7fc06ea
Typo: "Fix then " -> "Fix the "
Franz Glasner <fzglas.hg@dom66.de>
parents:
145
diff
changeset
|
28 -c ADDRESS Set the "CC:" header. |
| 111 | 29 |
| 110 | 30 -d n Does nothing. Just a compatibility option for `bsmtp`. |
| 31 | |
| 32 -f ADDRESS Set the "From:" header. | |
| 33 | |
| 34 -h MAILHOST:PORT Does nothing. Just a compatibility option for `bsmtp`. | |
| 35 | |
| 111 | 36 -l NUMBER Does nothing. Just a compatibility option for `bsmtp`. |
| 110 | 37 |
| 38 -r ADDRESS Set the "Reply-To:" header | |
| 39 | |
| 111 | 40 -s SUBJECT Set the "Subject:" header |
| 110 | 41 |
| 42 | |
|
123
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
43 Files: |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
44 |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
45 The shell style configuration file in |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
46 |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
47 @@ETCDIR@@/bsmtp2dma.conf is |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
48 |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
49 sourced in at script start. |
|
397bf58e85d2
Document configuration file usage
Franz Glasner <fzglas.hg@dom66.de>
parents:
121
diff
changeset
|
50 |
| 110 | 51 ' |
| 52 | |
| 53 # | |
| 54 # Configuration directory | |
| 55 # | |
| 56 : ${CONFIGDIR:=@@ETCDIR@@} | |
| 57 | |
| 58 test -r "${CONFIGDIR}/bsmtp2dma.conf" && . "${CONFIGDIR}/bsmtp2dma.conf" | |
| 59 | |
| 60 | |
| 111 | 61 # |
| 110 | 62 # Default configuration values |
| 111 | 63 # |
| 64 # `sendmail` is also valid for `dma` because of the mapping within | |
| 65 # `/etc/mail/mailer.conf` | |
| 66 # | |
| 110 | 67 : ${MAILER:=/usr/sbin/sendmail} |
| 68 | |
| 69 | |
| 70 parse_addr() { | |
| 71 : 'Parse an possibly complex email address. | |
| 72 | |
| 73 Addresses can be of the form | |
| 74 | |
| 75 - Name Parts <user@domain.tld> | |
| 76 - user@domain.tld | |
| 77 | |
| 78 `Name Parts` may not contain ``<`` or ``>`` characters. | |
| 79 | |
| 80 Args: | |
| 81 _addr: the complex email address | |
| 82 | |
| 83 Returns: | |
| 84 0 on success, 1 on errors | |
| 85 | |
| 86 Output (Globals): | |
| 87 email_name: the name part (or empty) | |
| 88 email_addr: the technical address part (or empty) | |
| 89 | |
| 90 ' | |
| 91 local _addr | |
| 92 | |
| 93 _addr="$1" | |
| 111 | 94 test -n "${_addr}" || return 1 |
| 110 | 95 |
| 96 if printf "%s" "${_addr}" | grep -q -E -e '^[^<>]+<[^<>]+@[^<>]+>$'; then | |
| 97 email_name=$(printf '%s' "${_addr}" | sed -E -e 's/[[:space:]]*<.+$//') | |
| 98 email_addr=$(printf '%s' "${_addr}" | sed -E -e 's/^[^<>]+<//' | sed -E -e 's/>$//') | |
| 99 return 0 | |
| 100 fi | |
| 101 if printf "%s" "${_addr}" | grep -q -E -e '^[^<>]+@[^<>]+$'; then | |
| 102 email_name="" | |
| 103 email_addr="${_addr}" | |
| 104 return 0 | |
| 105 fi | |
| 106 return 1 | |
| 107 } | |
| 108 | |
| 109 | |
| 110 send_mail() { | |
| 111 : 'Send the mail via the underlying configured mailer (dma, sendmail et al.). | |
| 112 | |
| 113 Args: | |
| 114 _recipient: The recipient name. | |
| 115 | |
| 116 Will be written into the "To:" header also. | |
| 117 | |
| 118 Input (Globals): | |
| 119 MAILER | |
| 120 MAILCONTENT | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
121 MAILFIFO_STDIN |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
122 MAILFIFO_STDOUT |
| 110 | 123 CC |
| 124 FROM | |
| 125 REPLYTO | |
| 126 SUBJECT | |
| 127 | |
| 128 Returns: | |
| 129 0 on success, other values on errors or the error exit code from the | |
| 130 underlying mailer | |
| 131 | |
| 111 | 132 This procedure starts the configured mailer as coproc and sends |
| 133 email headers and contents to the started mailer. | |
| 134 | |
| 110 | 135 ' |
| 111 | 136 local _recipient _rc _oifs _text _pid_mailer _recipient_addr |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
137 local _from_from _from_addr _sender_addr _dummy |
| 110 | 138 |
| 139 _recipient="$1" | |
| 140 _rc=0 | |
| 141 | |
| 111 | 142 if parse_addr "${_recipient}"; then |
| 143 _recipient_addr="${email_addr}" | |
| 144 else | |
| 145 echo "ERROR: unknown recipient address format in \`${_recipient}'" >&2 | |
| 146 return 1 | |
| 147 fi | |
| 148 _sender_addr="$(whoami)@$(hostname -f)" | |
| 149 if [ -z "${FROM}" ]; then | |
| 150 _from_addr="${_sender_addr}" | |
| 151 _from_from="${_from_addr}" | |
| 152 else | |
| 153 if parse_addr "${FROM}"; then | |
| 154 _from_from="${FROM}" | |
| 155 _from_addr="${email_addr}" | |
| 156 else | |
| 157 echo "ERROR: unknown sender name in \`${FROM}'" >&2 | |
| 158 return 1 | |
| 159 fi | |
| 160 fi | |
| 161 | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
162 mkfifo -m 0600 "${MAILFIFO_STDIN}" |
| 110 | 163 _rc=$? |
| 164 if [ ${_rc} -ne 0 ]; then | |
| 165 return ${_rc} | |
| 166 fi | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
167 mkfifo -m 0600 "${MAILFIFO_STDOUT}" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
168 _rc=$? |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
169 if [ ${_rc} -ne 0 ]; then |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
170 rm -f "${MAILFIFO_STDIN}" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
171 return ${_rc} |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
172 fi |
| 110 | 173 |
| 121 | 174 # |
| 175 # Start the mailer **before** opening the pipe; otherwise a | |
| 176 # deadlock occurs | |
| 177 # | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
178 "$MAILER" -f "${_sender_addr}" "${_recipient_addr}" <${MAILFIFO_STDIN} >${MAILFIFO_STDOUT} & |
| 110 | 179 _pid_mailer=$! |
| 180 | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
181 exec 3>"${MAILFIFO_STDIN}" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
182 exec 4<"${MAILFIFO_STDOUT}" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
183 |
| 111 | 184 printf "To: %s\n" "${_recipient}" >&3 |
| 185 printf "From: %s\n" "${_from_from}" >&3 | |
| 186 if [ "${_sender_addr}" != "${_from_addr}" ]; then | |
| 187 printf "Sender: %s\n" "${_sender_addr}" >&3 | |
| 188 fi | |
| 189 if [ -n "${SUBJECT}" ]; then | |
| 190 printf "Subject: %s\n" "${SUBJECT}" >&3 | |
| 191 fi | |
| 192 if [ -n "${REPLYTO}" ]; then | |
| 114 | 193 # |
| 194 # XXX TBD proper Reply-To header value checks: | |
| 195 # a comma separated list of full mail addresses | |
| 196 # | |
| 111 | 197 printf "Reply-To: %s\n" "${REPLYTO}" >&3 |
| 198 fi | |
| 199 if [ -n "${CC}" ]; then | |
| 114 | 200 # |
| 201 # XXX TBD proper CC header value checks: | |
| 202 # a comma separated list of full mail addresses | |
| 203 # | |
| 111 | 204 printf "Cc: %s\n" "${CC}" >&3 |
| 205 fi | |
| 206 printf "\n" >&3 | |
| 207 | |
| 208 # preserve leading white space when reading with `read` | |
| 110 | 209 _oifs="$IFS" |
| 210 IFS=" | |
| 211 " | |
| 212 cat "${MAILCONTENT}" | | |
| 213 while read _text; do | |
| 214 printf "%s\n" "$_text" >&3 | |
| 215 done | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
216 # not all mailer recognize this |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
217 # printf ".\n" >&3 |
| 110 | 218 IFS="$_oifs" |
| 219 | |
| 121 | 220 # close the fd to the pipe: coproc should get EOF and terminate |
| 110 | 221 exec 3>&- |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
222 # read eventually remaining stuff from the mailer until EOF |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
223 IFS='' read _dummy <&4 |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
224 exec 4<&- |
| 110 | 225 |
| 226 wait $_pid_mailer | |
| 227 _rc=$? | |
| 228 | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
229 # we are done with the named pipes |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
230 rm -f "${MAILFIFO_STDIN}" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
231 rm -f "${MAILFIFO_STDOUT}" |
| 110 | 232 |
| 233 return ${_rc} | |
| 234 } | |
| 235 | |
| 236 | |
| 111 | 237 while getopts "V8c:d:f:h:l:nr:s:" _opt; do |
| 110 | 238 case ${_opt} in |
| 239 V) | |
|
386
84d2735fe7f6
Simplified version tagging a lot: it is also faster now.
Franz Glasner <fzglas.hg@dom66.de>
parents:
317
diff
changeset
|
240 printf 'bsmtp2dma %s\n' '@@SIMPLEVERSIONSTR@@' |
| 110 | 241 echo "$USAGE" |
| 242 exit 0; | |
| 243 ;; | |
| 244 8) | |
| 245 : # VOID | |
| 246 ;; | |
| 247 c) | |
| 248 CC="$OPTARG" | |
| 249 ;; | |
| 111 | 250 d) |
| 251 : # VOID | |
| 252 ;; | |
| 110 | 253 f) |
| 254 FROM="$OPTARG" | |
| 255 ;; | |
| 256 h) | |
| 257 : # VOID | |
| 258 ;; | |
| 259 l) | |
| 260 : # VOID | |
| 261 ;; | |
| 262 r) | |
| 263 REPLYTO="$OPTARG" | |
| 264 ;; | |
| 265 s) | |
| 266 SUBJECT="$OPTARG" | |
| 267 ;; | |
| 268 \?) | |
| 269 exit 2; | |
| 270 ;; | |
| 271 *) | |
| 272 echo "ERROR: inconsistent option handling" >&2 | |
| 273 exit 2; | |
| 274 ;; | |
| 275 esac | |
| 276 done | |
| 277 | |
| 278 # return code | |
| 279 _rc=0 | |
| 280 | |
| 281 MAILTMPDIR="$(mktemp -d)" | |
|
119
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
282 MAILFIFO_STDIN="${MAILTMPDIR}/mail-stdin" |
|
5c92aeaec114
Try to make the mailer's input independent of a trailing single "." -- as opensmtpd's sendmail does not grok them.
Franz Glasner <fzglas.hg@dom66.de>
parents:
114
diff
changeset
|
283 MAILFIFO_STDOUT="${MAILTMPDIR}/mail-stdout" |
| 110 | 284 MAILCONTENT="${MAILTMPDIR}/mail-text" |
| 285 | |
| 286 # | |
| 287 # Clean up existing temporary stuff on all sorts of exit | |
| 288 # (including the "exit" call (signal 0)) | |
| 289 # | |
| 111 | 290 trap 'if [ -d "${MAILTMPDIR}" ]; then rm -rf "${MAILTMPDIR}"; fi; exit;' 0 1 2 15 |
| 110 | 291 |
| 292 test -d "${MAILTMPDIR}" || { echo "ERROR: no existing private tmp dir" >&2; exit 1; } | |
| 293 | |
| 294 # | |
| 295 # Reset the Shell's option handling system to prepare for handling | |
| 296 # other arguments and probably command-local options | |
| 297 # | |
| 298 shift $((OPTIND-1)) | |
| 299 OPTIND=1 | |
| 300 | |
| 301 # early check whether some recipients are given | |
| 302 if [ $# -eq 0 ]; then | |
| 303 echo "ERROR: no recipient given" >&2 | |
| 304 exit 2; | |
| 305 fi | |
| 306 | |
| 307 # | |
| 308 # Collect the mail text from stdin into a temporary file | |
| 309 # | |
| 310 exec 3>"${MAILCONTENT}" | |
| 111 | 311 # preserve leading white space when reading with `read` |
| 110 | 312 _oifs="$IFS" |
| 313 IFS=" | |
| 314 " | |
| 315 while read _text; do | |
| 316 if [ "${_text}" = "." ]; then | |
| 317 break | |
| 318 else | |
| 319 printf "%s\n" "${_text}" >&3 | |
| 320 fi | |
| 321 done | |
| 322 exec 3>&- | |
| 323 IFS="$_oifs" | |
| 324 | |
| 325 # | |
| 326 # Now send the content of the collected mail content to all recipients | |
| 327 # | |
| 328 until [ $# -eq 0 ]; do | |
| 329 send_mail "$1" | |
| 330 _rcsm=$? | |
| 331 if [ \( ${_rcsm} -ne 0 \) -a \( ${_rc} -eq 0 \) ]; then | |
| 332 _rc=${_rcsm} | |
| 333 fi | |
| 334 shift | |
| 335 done | |
| 336 | |
| 337 exit ${_rc} |
