diff options
author | EuAndreh <eu@euandre.org> | 2025-04-18 02:17:12 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2025-04-18 02:48:42 -0300 |
commit | 020c1e77489b772f854bb3288b9c8d2818a6bf9d (patch) | |
tree | 142aec725a52162a446ea7d947cb4347c9d573c9 /src/content/tils/2021/01 | |
parent | Makefile: Remove security.txt.gz (diff) | |
download | euandre.org-020c1e77489b772f854bb3288b9c8d2818a6bf9d.tar.gz euandre.org-020c1e77489b772f854bb3288b9c8d2818a6bf9d.tar.xz |
git mv src/content/* src/content/en/
Diffstat (limited to 'src/content/tils/2021/01')
-rw-r--r-- | src/content/tils/2021/01/12/curl-awk-emails.adoc | 148 | ||||
-rw-r--r-- | src/content/tils/2021/01/17/posix-shebang.adoc | 58 |
2 files changed, 0 insertions, 206 deletions
diff --git a/src/content/tils/2021/01/12/curl-awk-emails.adoc b/src/content/tils/2021/01/12/curl-awk-emails.adoc deleted file mode 100644 index d432da2..0000000 --- a/src/content/tils/2021/01/12/curl-awk-emails.adoc +++ /dev/null @@ -1,148 +0,0 @@ -= Awk snippet: send email to multiple recipients with cURL - -:neomutt: https://neomutt.org/ -:found-out-article: https://blog.edmdesigner.com/send-email-from-linux-command-line/ -:curl: https://curl.se/ - -As I experiment with {neomutt}[Neomutt], I wanted to keep being able to enqueue -emails for sending later like my previous setup, so that I didn't rely on having -an internet connection. - -My requirements for the `sendmail` command were: - -. store the email in a file, and send it later; -. send from different addresses, using different SMTP servers. - -I couldn't find an MTA that could accomplish that, but I was able to quickly -write a solution. - -The first part was the easiest: store the email in a file: - -[source,sh] ----- -# ~/.config/mutt/muttrc: -set sendmail=~/bin/enqueue-email.sh - -# ~/bin/enqueue-email.sh: -#!/bin/sh -eu - -cat - > "$HOME/mbsync/my-queued-emails/$(date -Is)" ----- - -Now that I had the email file store locally, I needed a program to send the -email from the file, so that I could create a cronjob like: - -[source,sh] ----- -for f in ~/mbsync/my-queued-emails/*; do - ~/bin/dispatch-email.sh "$f" && rm "$f" -done ----- - -The `dispatch-email.sh` would have to look at the `From:` header and decide -which SMTP server to use. As I {found-out-article}[found out] that {curl}[curl] -supports SMTP and is able to send emails, this is what I ended up with: - -[source,sh] ----- -#!/bin/sh -eu - -F="$1" - -rcpt="$(awk ' - match($0, /^(To|Cc|Bcc): (.*)$/, m) { - split(m[2], tos, ",") - for (i in tos) { - print "--mail-rcpt " tos[i] - } - } -' "$F")" - -if grep -qE '^From: .*<addr@server1\.org>$' "$F"; then - curl \ - -s \ - --url smtp://smtp.server1.org:587 \ - --ssl-reqd \ - --mail-from addr@server1.org \ - $rcpt \ - --user 'addr@server1.org:my-long-and-secure-passphrase' \ - --upload-file "$F" -elif grep -qE '^From: .*<addr@server2\.org>$' "$F"; then - curl \ - -s \ - --url smtp://smtp.server2.org:587 \ - --ssl-reqd \ - --mail-from addr@server2.org \ - $rcpt \ - --user 'addr@server2.org:my-long-and-secure-passphrase' \ - --upload-file "$F" -else - echo 'Bad "From: " address' - exit 1 -fi ----- - -Most of curl flags used are self-explanatory, except for `$rcpt`. - -curl connects to the SMTP server, but doesn't set the recipient address by -looking at the message. My solution was to generate the curl flags, store them -in `$rcpt` and use it unquoted to leverage shell word splitting. - -To me, the most interesting part was building the `$rcpt` flags. My first -instinct was to try grep, but it couldn't print only matches in a regex. As I -started to turn towards sed, I envisioned needing something else to loop over -the sed output, and I then moved to Awk. - -In the short Awk snippet, 3 things were new to me: the `match(...)`, -`split(...)` and `for () {}`. The only other function I have ever used was -`gsub(...)`, but these new ones felt similar enough that I could almost guess -their behaviour and arguments. `match(...)` stores the matches of a regex on -the given array positionally, and `split(...)` stores the chunks in the given -array. - -I even did it incrementally: - -[source,sh] ----- -$ H='To: to@example.com, to2@example.com\nCc: cc@example.com, cc2@example.com\nBcc: bcc@example.com,bcc2@example.com\n' -$ printf "$H" | awk '/^To: .*$/ { print $0 }' -To: to@example.com, to2@example.com -$ printf "$H" | awk 'match($0, /^To: (.*)$/, m) { print m }' -awk: ligne de commande:1: (FILENAME=- FNR=1) fatal : tentative d'utilisation du tableau « m » dans un contexte scalaire -$ printf "$H" | awk 'match($0, /^To: (.*)$/, m) { print m[0] }' -To: to@example.com, to2@example.com -$ printf "$H" | awk 'match($0, /^To: (.*)$/, m) { print m[1] }' -to@example.com, to2@example.com -$ printf "$H" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, " "); print tos }' -awk: ligne de commande:1: (FILENAME=- FNR=1) fatal : tentative d'utilisation du tableau « tos » dans un contexte scalaire -$ printf "$H" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, " "); print tos[0] }' - -$ printf "$H" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, " "); print tos[1] }' -to@example.com, -$ printf "$H" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, " "); print tos[2] }' -to2@example.com -$ printf "$H" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, " "); print tos[3] }' ----- - -(This isn't the verbatim interactive session, but a cleaned version to make it -more readable.) - -At this point, I realized I needed a for loop over the `tos` array, and I moved -the Awk snippet into the `~/bin/dispatch-email.sh`. I liked the final thing: - -[source,awk] ----- -match($0, /^(To|Cc|Bcc): (.*)$/, m) { - split(m[2], tos, ",") - for (i in tos) { - print "--mail-rcpt " tos[i] - } -} ----- - -As I learn more about Awk, I feel that it is too undervalued, as many people -turn to Perl or other programming languages when Awk suffices. The advantage is -pretty clear: writing programs that run on any POSIX system, without extra -dependencies required. - -Coding to the standards is underrated. diff --git a/src/content/tils/2021/01/17/posix-shebang.adoc b/src/content/tils/2021/01/17/posix-shebang.adoc deleted file mode 100644 index 5cf0695..0000000 --- a/src/content/tils/2021/01/17/posix-shebang.adoc +++ /dev/null @@ -1,58 +0,0 @@ -= POSIX sh and shebangs - -:awk-1: link:../../../2020/12/15/shellcheck-repo.html -:awk-2: link:../12/curl-awk-emails.html - -As I {awk-1}[keep moving] {awk-2}[towards POSIX], I'm on the process of -migrating all my Bash scripts to POSIX sh. - -As I dropped `[[`, arrays and other Bashisms, I was left staring at the first -line of every script, wondering what to do: what is the POSIX sh equivalent of -`#!/usr/bin/env bash`? I already knew that POSIX says nothing about shebangs, -and that the portable way to call a POSIX sh script is `sh script.sh`, but -I didn't know what to do with that first line. - -What I had previously was: - -[source,sh] ----- -#!/usr/bin/env bash -set -Eeuo pipefail -cd "$(dirname "${BASH_SOURCE[0]}")" ----- - -Obviously, the `$BASH_SOURCE` would be gone, and I would have to adapt some of -my scripts to not rely on the script location. The `-E` and `-o pipefail` -options were also gone, and would be replaced by nothing. - -I converted all of them to: - -[source,sh] ----- -#!/bin/sh -eu ----- - -I moved the `-eu` options to the shebang line itself, striving for conciseness. -But as I changed callers from `./script.sh` to `sh script.sh`, things started to -fail. Some tests that should fail reported errors, but didn't return 1. - -My first reaction was to revert back to `./script.sh`, but the POSIX bug I -caught is a strong strain, and when I went back to it, I figured that the -callers were missing some flags. Specifically, `sh -eu script.sh`. - -Then it clicked: when running with `sh script.sh`, the shebang line with the sh -options is ignored, as it is a comment! - -Which means that the shebang most friendly with POSIX is: - -[source,sh] ----- -#!/bin/sh -set -eu ----- - -. when running via `./script.sh`, if the system has an executable at `/bin/sh`, - it will be used to run the script; -. when running via `sh script.sh`, the sh options aren't ignored as previously. - -TIL. |