From e8315dde44eea32122ef39a02e9cfd90cbeb6fff Mon Sep 17 00:00:00 2001 From: EuAndreh Date: Tue, 12 Jan 2021 15:33:46 -0300 Subject: Add another TIL on AWK: curl flags --- ...-send-email-to-multiple-recipients-with-curl.md | 142 ++++++++++++ ...-send-email-to-multiple-recipients-with-curl.po | 243 +++++++++++++++++++++ ...-send-email-to-multiple-recipients-with-curl.po | 243 +++++++++++++++++++++ ...-send-email-to-multiple-recipients-with-curl.po | 243 +++++++++++++++++++++ scripts/spelling/international.txt | 8 + 5 files changed, 879 insertions(+) create mode 100644 _tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.md create mode 100644 locale/eo/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po create mode 100644 locale/fr/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po create mode 100644 locale/pt/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po diff --git a/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.md b/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.md new file mode 100644 index 0000000..3ac5b97 --- /dev/null +++ b/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.md @@ -0,0 +1,142 @@ +--- + +title: 'Awk snippet: send email to multiple recipients with cURL' + +date: 2021-01-12 + +layout: post + +lang: en + +ref: awk-snippet-send-email-to-multiple-recipients-with-curl + +--- + +As I experimented 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: +1. store the email in a file, and send it later. +1. 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: + +```shell +# ~/.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: + +```shell +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][curl-email] that [curl][curl] supports SMTP and is able to send emails, this is what I ended up with: + +```shell +#!/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: .*$' "$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: .*$' "$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: + +```shell +$ 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: + +```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. + +[neomutt]: https://neomutt.org/ +[curl-email]: https://blog.edmdesigner.com/send-email-from-linux-command-line/ +[curl]: https://curl.se/ diff --git a/locale/eo/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po b/locale/eo/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po new file mode 100644 index 0000000..7561292 --- /dev/null +++ b/locale/eo/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po @@ -0,0 +1,243 @@ +# +msgid "" +msgstr "" + +msgid "title: 'Awk snippet: send email to multiple recipients with cURL'" +msgstr "" + +msgid "date: 2021-01-12" +msgstr "" + +msgid "layout: post" +msgstr "" + +msgid "lang: en" +msgstr "" + +msgid "ref: awk-snippet-send-email-to-multiple-recipients-with-curl" +msgstr "" + +msgid "My requirements for the `sendmail` command were:" +msgstr "" + +msgid "store the email in a file, and send it later." +msgstr "" + +msgid "send from different addresses, using different SMTP servers;" +msgstr "" + +msgid "" +"I couldn't find an MTA that could accomplish that, but I was able to quickly" +" write a solution." +msgstr "" + +msgid "The first part was the easiest: store the email in a file:" +msgstr "" + +msgid "" +"# ~/.config/mutt/muttrc:\n" +"set sendmail=~/bin/enqueue-email.sh\n" +"\n" +"# ~/bin/enqueue-email.sh:\n" +"#!/bin/sh -eu\n" +"\n" +"cat - > \"$HOME/mbsync/my-queued-emails/$(date -Is)\"\n" +msgstr "" + +msgid "" +"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:" +msgstr "" + +msgid "" +"for f in ~/mbsync/my-queued-emails/*; do\n" +" ~/bin/dispatch-email.sh \"$f\" && rm \"$f\"\n" +"done\n" +msgstr "" + +msgid "" +"The `dispatch-email.sh` would have to look at the `From: ` header and decide" +" which SMTP server to use. As I [found " +"out](https://blog.edmdesigner.com/send-email-from-linux-command-line/) that " +"[curl](https://curl.se/) supports SMTP and is able to send emails, this is " +"what I ended up with:" +msgstr "" + +msgid "Most of curl flags used are self-explanatory, except for `$rcpt`." +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "" +"$ H='To: to@example.com, to2@example.com\\nCc: cc@example.com, cc2@example.com\\nBcc: bcc@example.com,bcc2@example.com\\n'\n" +"$ printf \"$H\" | awk '/^To: .*$/ { print $0 }'\n" +"To: to@example.com, to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { print m }'\n" +"awk: ligne de commande:1: (FILENAME=- FNR=1) fatal : tentative d'utilisation du tableau « m » dans un contexte scalaire\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { print m[0] }'\n" +"To: to@example.com, to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { print m[1] }'\n" +"to@example.com, to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos }'\n" +"awk: ligne de commande:1: (FILENAME=- FNR=1) fatal : tentative d'utilisation du tableau « tos » dans un contexte scalaire\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[0] }'\n" +"\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[1] }'\n" +"to@example.com,\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[2] }'\n" +"to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[3] }'\n" +"\n" +msgstr "" + +msgid "" +"(This isn't the verbatim interactive session, but a cleaned version to make " +"it more readable.)" +msgstr "" + +msgid "" +"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:" +msgstr "" + +msgid "" +"match($0, /^(To|Cc|Bcc): (.*)$/, m) {\n" +" split(m[2], tos, \",\")\n" +" for (i in tos) {\n" +" print \"--mail-rcpt \" tos[i]\n" +" }\n" +"}\n" +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "Coding to the standards is underrated." +msgstr "" + +msgid "" +"#!/bin/sh -eu\n" +"\n" +"F=\"$1\"\n" +"\n" +"rcpt=\"$(awk '\n" +" match($0, /^(To|Cc|Bcc): (.*)$/, m) {\n" +" split(m[2], tos, \",\")\n" +" for (i in tos) {\n" +" print \"--mail-rcpt \" tos[i]\n" +" }\n" +" }\n" +"' \"$F\")\"\n" +"\n" +"if grep -qE '^From: .*$' \"$F\"; then\n" +" curl \\\n" +" -s \\\n" +" --url smtp://smtp.server1.org:587 \\\n" +" --ssl-reqd \\\n" +" --mail-from addr@server1.org \\\n" +" $rcpt \\\n" +" --user 'addr@server1.org:my-long-and-secure-passphrase' \\\n" +" --upload-file \"$F\"\n" +"elif grep -qE '^From: .*$' \"$F\"; then\n" +" curl \\\n" +" -s \\\n" +" --url smtp://smtp.server2.org:587 \\\n" +" --ssl-reqd \\\n" +" --mail-from addr@server2.org \\\n" +" $rcpt \\\n" +" --user 'addr@server2.org:my-long-and-secure-passphrase' \\\n" +" --upload-file \"$F\"\n" +"else\n" +" echo 'Bad \"From: \" address'\n" +" exit 1\n" +"fi\n" +msgstr "" + +msgid "" +"As I experimented with [Neomutt](https://neomutt.org/), 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." +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "I even did it incrementally:" +msgstr "" + +#~ msgid "I even did this incrementally:" +#~ msgstr "" + +#~ msgid "" +#~ "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 felt similar enough that I could almost guess " +#~ "their behaviour. `match(...)` stores the matches of a regex on the given " +#~ "array positionally, and `split(...)` stores the chunks in the given array." +#~ msgstr "" + +#~ msgid "" +#~ "As I experimented with [Neomutt](https://neomutt.org/), I wanted to keep " +#~ "being able to enqueue emails for sending later, so that I didn't rely on " +#~ "having an internet connection." +#~ msgstr "" + +#~ msgid "" +#~ "#!/bin/sh -eu\n" +#~ "\n" +#~ "F=\"$1\"\n" +#~ "\n" +#~ "rcpt=\"$(awk '\n" +#~ " match($0, /^(To|Cc|Bcc): (.*)$/, m) {\n" +#~ " split(m[2], tos, \",\")\n" +#~ " for (i in tos) {\n" +#~ " print \"--mail-rcpt \" tos[i]\n" +#~ " }\n" +#~ " }\n" +#~ "' \"$F\")\"\n" +#~ "\n" +#~ "if grep -qE '^From: .*$' \"$F\"; then\n" +#~ " curl \\\n" +#~ " -s \\\n" +#~ " --url smtp://smtp.server1.org:587 \\\n" +#~ " --ssl-reqd \\\n" +#~ " --mail-from addr@server1.org \\\n" +#~ " $rcpt \\\n" +#~ " --user 'addr@server1.org:my-long-and-secure-passphrase' \\\n" +#~ " --upload-file \"$F\"\n" +#~ "eliif grep -qE '^From: .*$' \"$F\"; then\n" +#~ " curl \\\n" +#~ " -s \\\n" +#~ " --url smtp://smtp.server2.org:587 \\\n" +#~ " --ssl-reqd \\\n" +#~ " --mail-from addr@server2.org \\\n" +#~ " $rcpt \\\n" +#~ " --user 'addr@server2.org:my-long-and-secure-passphrase' \\\n" +#~ " --upload-file \"$F\"\n" +#~ "else\n" +#~ " echo 'Bad \"From: \" address'\n" +#~ " exit 1\n" +#~ "fi\n" +#~ msgstr "" diff --git a/locale/fr/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po b/locale/fr/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po new file mode 100644 index 0000000..7561292 --- /dev/null +++ b/locale/fr/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po @@ -0,0 +1,243 @@ +# +msgid "" +msgstr "" + +msgid "title: 'Awk snippet: send email to multiple recipients with cURL'" +msgstr "" + +msgid "date: 2021-01-12" +msgstr "" + +msgid "layout: post" +msgstr "" + +msgid "lang: en" +msgstr "" + +msgid "ref: awk-snippet-send-email-to-multiple-recipients-with-curl" +msgstr "" + +msgid "My requirements for the `sendmail` command were:" +msgstr "" + +msgid "store the email in a file, and send it later." +msgstr "" + +msgid "send from different addresses, using different SMTP servers;" +msgstr "" + +msgid "" +"I couldn't find an MTA that could accomplish that, but I was able to quickly" +" write a solution." +msgstr "" + +msgid "The first part was the easiest: store the email in a file:" +msgstr "" + +msgid "" +"# ~/.config/mutt/muttrc:\n" +"set sendmail=~/bin/enqueue-email.sh\n" +"\n" +"# ~/bin/enqueue-email.sh:\n" +"#!/bin/sh -eu\n" +"\n" +"cat - > \"$HOME/mbsync/my-queued-emails/$(date -Is)\"\n" +msgstr "" + +msgid "" +"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:" +msgstr "" + +msgid "" +"for f in ~/mbsync/my-queued-emails/*; do\n" +" ~/bin/dispatch-email.sh \"$f\" && rm \"$f\"\n" +"done\n" +msgstr "" + +msgid "" +"The `dispatch-email.sh` would have to look at the `From: ` header and decide" +" which SMTP server to use. As I [found " +"out](https://blog.edmdesigner.com/send-email-from-linux-command-line/) that " +"[curl](https://curl.se/) supports SMTP and is able to send emails, this is " +"what I ended up with:" +msgstr "" + +msgid "Most of curl flags used are self-explanatory, except for `$rcpt`." +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "" +"$ H='To: to@example.com, to2@example.com\\nCc: cc@example.com, cc2@example.com\\nBcc: bcc@example.com,bcc2@example.com\\n'\n" +"$ printf \"$H\" | awk '/^To: .*$/ { print $0 }'\n" +"To: to@example.com, to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { print m }'\n" +"awk: ligne de commande:1: (FILENAME=- FNR=1) fatal : tentative d'utilisation du tableau « m » dans un contexte scalaire\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { print m[0] }'\n" +"To: to@example.com, to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { print m[1] }'\n" +"to@example.com, to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos }'\n" +"awk: ligne de commande:1: (FILENAME=- FNR=1) fatal : tentative d'utilisation du tableau « tos » dans un contexte scalaire\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[0] }'\n" +"\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[1] }'\n" +"to@example.com,\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[2] }'\n" +"to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[3] }'\n" +"\n" +msgstr "" + +msgid "" +"(This isn't the verbatim interactive session, but a cleaned version to make " +"it more readable.)" +msgstr "" + +msgid "" +"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:" +msgstr "" + +msgid "" +"match($0, /^(To|Cc|Bcc): (.*)$/, m) {\n" +" split(m[2], tos, \",\")\n" +" for (i in tos) {\n" +" print \"--mail-rcpt \" tos[i]\n" +" }\n" +"}\n" +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "Coding to the standards is underrated." +msgstr "" + +msgid "" +"#!/bin/sh -eu\n" +"\n" +"F=\"$1\"\n" +"\n" +"rcpt=\"$(awk '\n" +" match($0, /^(To|Cc|Bcc): (.*)$/, m) {\n" +" split(m[2], tos, \",\")\n" +" for (i in tos) {\n" +" print \"--mail-rcpt \" tos[i]\n" +" }\n" +" }\n" +"' \"$F\")\"\n" +"\n" +"if grep -qE '^From: .*$' \"$F\"; then\n" +" curl \\\n" +" -s \\\n" +" --url smtp://smtp.server1.org:587 \\\n" +" --ssl-reqd \\\n" +" --mail-from addr@server1.org \\\n" +" $rcpt \\\n" +" --user 'addr@server1.org:my-long-and-secure-passphrase' \\\n" +" --upload-file \"$F\"\n" +"elif grep -qE '^From: .*$' \"$F\"; then\n" +" curl \\\n" +" -s \\\n" +" --url smtp://smtp.server2.org:587 \\\n" +" --ssl-reqd \\\n" +" --mail-from addr@server2.org \\\n" +" $rcpt \\\n" +" --user 'addr@server2.org:my-long-and-secure-passphrase' \\\n" +" --upload-file \"$F\"\n" +"else\n" +" echo 'Bad \"From: \" address'\n" +" exit 1\n" +"fi\n" +msgstr "" + +msgid "" +"As I experimented with [Neomutt](https://neomutt.org/), 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." +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "I even did it incrementally:" +msgstr "" + +#~ msgid "I even did this incrementally:" +#~ msgstr "" + +#~ msgid "" +#~ "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 felt similar enough that I could almost guess " +#~ "their behaviour. `match(...)` stores the matches of a regex on the given " +#~ "array positionally, and `split(...)` stores the chunks in the given array." +#~ msgstr "" + +#~ msgid "" +#~ "As I experimented with [Neomutt](https://neomutt.org/), I wanted to keep " +#~ "being able to enqueue emails for sending later, so that I didn't rely on " +#~ "having an internet connection." +#~ msgstr "" + +#~ msgid "" +#~ "#!/bin/sh -eu\n" +#~ "\n" +#~ "F=\"$1\"\n" +#~ "\n" +#~ "rcpt=\"$(awk '\n" +#~ " match($0, /^(To|Cc|Bcc): (.*)$/, m) {\n" +#~ " split(m[2], tos, \",\")\n" +#~ " for (i in tos) {\n" +#~ " print \"--mail-rcpt \" tos[i]\n" +#~ " }\n" +#~ " }\n" +#~ "' \"$F\")\"\n" +#~ "\n" +#~ "if grep -qE '^From: .*$' \"$F\"; then\n" +#~ " curl \\\n" +#~ " -s \\\n" +#~ " --url smtp://smtp.server1.org:587 \\\n" +#~ " --ssl-reqd \\\n" +#~ " --mail-from addr@server1.org \\\n" +#~ " $rcpt \\\n" +#~ " --user 'addr@server1.org:my-long-and-secure-passphrase' \\\n" +#~ " --upload-file \"$F\"\n" +#~ "eliif grep -qE '^From: .*$' \"$F\"; then\n" +#~ " curl \\\n" +#~ " -s \\\n" +#~ " --url smtp://smtp.server2.org:587 \\\n" +#~ " --ssl-reqd \\\n" +#~ " --mail-from addr@server2.org \\\n" +#~ " $rcpt \\\n" +#~ " --user 'addr@server2.org:my-long-and-secure-passphrase' \\\n" +#~ " --upload-file \"$F\"\n" +#~ "else\n" +#~ " echo 'Bad \"From: \" address'\n" +#~ " exit 1\n" +#~ "fi\n" +#~ msgstr "" diff --git a/locale/pt/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po b/locale/pt/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po new file mode 100644 index 0000000..7561292 --- /dev/null +++ b/locale/pt/LC_MESSAGES/_tils/2021-01-12-awk-snippet-send-email-to-multiple-recipients-with-curl.po @@ -0,0 +1,243 @@ +# +msgid "" +msgstr "" + +msgid "title: 'Awk snippet: send email to multiple recipients with cURL'" +msgstr "" + +msgid "date: 2021-01-12" +msgstr "" + +msgid "layout: post" +msgstr "" + +msgid "lang: en" +msgstr "" + +msgid "ref: awk-snippet-send-email-to-multiple-recipients-with-curl" +msgstr "" + +msgid "My requirements for the `sendmail` command were:" +msgstr "" + +msgid "store the email in a file, and send it later." +msgstr "" + +msgid "send from different addresses, using different SMTP servers;" +msgstr "" + +msgid "" +"I couldn't find an MTA that could accomplish that, but I was able to quickly" +" write a solution." +msgstr "" + +msgid "The first part was the easiest: store the email in a file:" +msgstr "" + +msgid "" +"# ~/.config/mutt/muttrc:\n" +"set sendmail=~/bin/enqueue-email.sh\n" +"\n" +"# ~/bin/enqueue-email.sh:\n" +"#!/bin/sh -eu\n" +"\n" +"cat - > \"$HOME/mbsync/my-queued-emails/$(date -Is)\"\n" +msgstr "" + +msgid "" +"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:" +msgstr "" + +msgid "" +"for f in ~/mbsync/my-queued-emails/*; do\n" +" ~/bin/dispatch-email.sh \"$f\" && rm \"$f\"\n" +"done\n" +msgstr "" + +msgid "" +"The `dispatch-email.sh` would have to look at the `From: ` header and decide" +" which SMTP server to use. As I [found " +"out](https://blog.edmdesigner.com/send-email-from-linux-command-line/) that " +"[curl](https://curl.se/) supports SMTP and is able to send emails, this is " +"what I ended up with:" +msgstr "" + +msgid "Most of curl flags used are self-explanatory, except for `$rcpt`." +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "" +"$ H='To: to@example.com, to2@example.com\\nCc: cc@example.com, cc2@example.com\\nBcc: bcc@example.com,bcc2@example.com\\n'\n" +"$ printf \"$H\" | awk '/^To: .*$/ { print $0 }'\n" +"To: to@example.com, to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { print m }'\n" +"awk: ligne de commande:1: (FILENAME=- FNR=1) fatal : tentative d'utilisation du tableau « m » dans un contexte scalaire\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { print m[0] }'\n" +"To: to@example.com, to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { print m[1] }'\n" +"to@example.com, to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos }'\n" +"awk: ligne de commande:1: (FILENAME=- FNR=1) fatal : tentative d'utilisation du tableau « tos » dans un contexte scalaire\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[0] }'\n" +"\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[1] }'\n" +"to@example.com,\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[2] }'\n" +"to2@example.com\n" +"$ printf \"$H\" | awk 'match($0, /^To: (.*)$/, m) { split(m[1], tos, \" \"); print tos[3] }'\n" +"\n" +msgstr "" + +msgid "" +"(This isn't the verbatim interactive session, but a cleaned version to make " +"it more readable.)" +msgstr "" + +msgid "" +"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:" +msgstr "" + +msgid "" +"match($0, /^(To|Cc|Bcc): (.*)$/, m) {\n" +" split(m[2], tos, \",\")\n" +" for (i in tos) {\n" +" print \"--mail-rcpt \" tos[i]\n" +" }\n" +"}\n" +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "Coding to the standards is underrated." +msgstr "" + +msgid "" +"#!/bin/sh -eu\n" +"\n" +"F=\"$1\"\n" +"\n" +"rcpt=\"$(awk '\n" +" match($0, /^(To|Cc|Bcc): (.*)$/, m) {\n" +" split(m[2], tos, \",\")\n" +" for (i in tos) {\n" +" print \"--mail-rcpt \" tos[i]\n" +" }\n" +" }\n" +"' \"$F\")\"\n" +"\n" +"if grep -qE '^From: .*$' \"$F\"; then\n" +" curl \\\n" +" -s \\\n" +" --url smtp://smtp.server1.org:587 \\\n" +" --ssl-reqd \\\n" +" --mail-from addr@server1.org \\\n" +" $rcpt \\\n" +" --user 'addr@server1.org:my-long-and-secure-passphrase' \\\n" +" --upload-file \"$F\"\n" +"elif grep -qE '^From: .*$' \"$F\"; then\n" +" curl \\\n" +" -s \\\n" +" --url smtp://smtp.server2.org:587 \\\n" +" --ssl-reqd \\\n" +" --mail-from addr@server2.org \\\n" +" $rcpt \\\n" +" --user 'addr@server2.org:my-long-and-secure-passphrase' \\\n" +" --upload-file \"$F\"\n" +"else\n" +" echo 'Bad \"From: \" address'\n" +" exit 1\n" +"fi\n" +msgstr "" + +msgid "" +"As I experimented with [Neomutt](https://neomutt.org/), 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." +msgstr "" + +msgid "" +"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." +msgstr "" + +msgid "I even did it incrementally:" +msgstr "" + +#~ msgid "I even did this incrementally:" +#~ msgstr "" + +#~ msgid "" +#~ "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 felt similar enough that I could almost guess " +#~ "their behaviour. `match(...)` stores the matches of a regex on the given " +#~ "array positionally, and `split(...)` stores the chunks in the given array." +#~ msgstr "" + +#~ msgid "" +#~ "As I experimented with [Neomutt](https://neomutt.org/), I wanted to keep " +#~ "being able to enqueue emails for sending later, so that I didn't rely on " +#~ "having an internet connection." +#~ msgstr "" + +#~ msgid "" +#~ "#!/bin/sh -eu\n" +#~ "\n" +#~ "F=\"$1\"\n" +#~ "\n" +#~ "rcpt=\"$(awk '\n" +#~ " match($0, /^(To|Cc|Bcc): (.*)$/, m) {\n" +#~ " split(m[2], tos, \",\")\n" +#~ " for (i in tos) {\n" +#~ " print \"--mail-rcpt \" tos[i]\n" +#~ " }\n" +#~ " }\n" +#~ "' \"$F\")\"\n" +#~ "\n" +#~ "if grep -qE '^From: .*$' \"$F\"; then\n" +#~ " curl \\\n" +#~ " -s \\\n" +#~ " --url smtp://smtp.server1.org:587 \\\n" +#~ " --ssl-reqd \\\n" +#~ " --mail-from addr@server1.org \\\n" +#~ " $rcpt \\\n" +#~ " --user 'addr@server1.org:my-long-and-secure-passphrase' \\\n" +#~ " --upload-file \"$F\"\n" +#~ "eliif grep -qE '^From: .*$' \"$F\"; then\n" +#~ " curl \\\n" +#~ " -s \\\n" +#~ " --url smtp://smtp.server2.org:587 \\\n" +#~ " --ssl-reqd \\\n" +#~ " --mail-from addr@server2.org \\\n" +#~ " $rcpt \\\n" +#~ " --user 'addr@server2.org:my-long-and-secure-passphrase' \\\n" +#~ " --upload-file \"$F\"\n" +#~ "else\n" +#~ " echo 'Bad \"From: \" address'\n" +#~ " exit 1\n" +#~ "fi\n" +#~ msgstr "" diff --git a/scripts/spelling/international.txt b/scripts/spelling/international.txt index 7c2d678..9b14732 100644 --- a/scripts/spelling/international.txt +++ b/scripts/spelling/international.txt @@ -81,6 +81,7 @@ LaTeX Lerna LilyPond LiquidHaskell +MTA Mailutils Marcha Marinheiros @@ -89,6 +90,7 @@ McGranaghan Mentat Merkle NPM +Neomutt Nextcloud NixOS Nixpkgs @@ -113,7 +115,9 @@ Raku Reddit Redux SA +SMTP SSD +SSMTP SVG Saudade Screencast @@ -150,12 +154,14 @@ boneco br brainer buildGoModule +cURL cargo2nix carte cbindgen cgit ci clojure +cronjob da datalog datom @@ -218,6 +224,7 @@ org pastebin pastebins plaintext +positionally pouchdb progn pt @@ -226,6 +233,7 @@ rollouts sbcl screencast screencasts +sed songbooks sourcehut sr -- cgit v1.2.3