email: properly set headers if no PGP configured
If neither the instance nor the recipient has a PGP key, the codepath
(correctly) sets the message body to the plain text but uses a fresh set
of headers, so all configured headers get dropped, including subject and
from.
While the service is certainly intended to be run with PGP configured it
makes sense to keep this option reasonably functional for testing and
development purposes.
This commit fixes the issue by initializing the header set to the
already configured headers if neither encryption nor signing is used.
Don't uppercase error messages
email/worker: catch some PGP error earlier
The writer returned by pgpmail.Encryption() will have the keyring
parsed, but it only tries to determine the encryption key once it is
being written to. Hence, certain errors will only occur later on, when
it is too late to fall back to unencrypted email.
Catch these errors earlier by checking if a valid encryption key is
found.
all: pass errors to panic, not strings
GraphQL's recovery middleware can't handle strings so it just logs a
very not useful <nil>
email: fix partial bodies
Depending on the email and buffer size, cleartext.Close() and
body.Close() may happen *after* buf.Bytes() is called; producing
incomplete emails, interrupted in the middle of the body.
Make sure to close both *before* getting the buffer contents.
Fixes: db4d67a2a6fb ("email: fix empty emails sent on retries")
Signed-off-by: Robin Jarry <robin@jarry.cc>
email: fix empty emails sent on retries
io.Reader objects can only be consumed once. On retry, re-reading from
them will return 0 bytes all the time.
Change NewTask to take in a bytes array instead of a reader. Create
a new reader on each retry.
Also remove SendRaw which has an inherent issue related to retry as
well. message.Entity is virtually a reader that can only be consumed
once.
Update EnqueueRaw to take a bytes array directly and have it call
NewTask() like EnqueueStd does.
Fixes: 78cfc5d87a7d ("email: allow sending raw emails")
Signed-off-by: Robin Jarry <robin@jarry.cc>
config: factorize integer parsing
Add a new GetInt() function to parse an integer value from a parsed
ini.File. Use that function instead of duplicated code.
Signed-off-by: Robin Jarry <robin@jarry.cc>
email: allow sending raw emails
The current email.Enqueue() function only allows sending messages with
the server's default settings.
In order to support sending any arbitrary message, we need to expose
a lower level API taking a raw message.Entity pointer. This new API will
be reused in a future reimplementation of the lists.sr.ht ingress agent
to forward messages to subscribers.
Add email.EnqueueRaw() that calls email.SendRaw(). Retry sending 10
times in the case of failure.
Signed-off-by: Robin Jarry <robin@jarry.cc>
email: keep smtp client connection alive
Instead of connecting and disconnecting each and every time we need to
send an email, keep the SMTP connection alive attached to a context
variable.
Before sending an email, check if the connection is still valid and
reconnect if it is not.
Signed-off-by: Robin Jarry <robin@jarry.cc>
treewide: update to new multi worker dowork api
The work.Queue() implementation has changed and now allows scheduling
tasks from multiple goroutines in parallel. Also, it requires a new
argument for limiting the queue buffer size in order to apply back
pressure.
Define new configuration variables to allow tuning the queue sizes and
number of workers per service:
[mail]
# Maximum size of the outgoing email queue (default 512).
egress-queue-size = 512
[$service_name]
# Number of parallel workers per queue (default 1).
# There are multiple queues (for egress email, webhooks, etc.).
# This setting is applied on a per-queue basis.
queue-workers = 1
[webhooks]
# Maximum size of the webhooks queue (default 512).
queue-size = 512
Use these new settings to configure the queues and workers accordingly.
Fix unit tests as well.
Link: https://git.sr.ht/~sircmpwn/dowork/commit/95719cfc0118
Signed-off-by: Robin Jarry <robin@jarry.cc>
email: set Content-Type to format=flowed
This allows us to start sending emails in flowed format. It does not
actually change anything, until the templates in the services get
updated.
As format=flowed is designed to be backwards-compatible, it also doesn't
break anything. All emails will still look like before, with static line
breaks. However, changing the templates to flowed will now produce
emails that render as flowed successfully. Tested on plain (signed) and
encrypted mails.
See https://www.ietf.org/rfc/rfc2646.txt
email: make PGP private key optional
Services other than meta.sr.ht don't really have a use for the
private PGP key.
Add a CanPGPSign method so that meta.sr.ht can emit a warning or
error when the PGP key is missing.
email: improve mail.ParseAddress error message
email: EnqueueStd: set Content-Type with charset=UTF-8 instead of just text/plain
Mails are now
--11d2cbf164a9ae0dfbb310faf818762607dcfd20aa74e07c7be0eec1458d
Mime-Version: 1.0
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
=D1=82=D1=80=D1=83=D0=BF=D0=B08
--=20
View on the web: http://192.168.1.101:5003/~nab2/trupa/8
--11d2cbf164a9ae0dfbb310faf818762607dcfd20aa74e07c7be0eec1458d
Content-Type: application/pgp-signature
-----BEGIN PGP MESSAGE-----
wnUEARYIACcFAmUavj0JkKdioLsBS5scFiEE+ts/9LaoXcZuSmrHp2KguwFLmxwA
AIm9AP9KB4cZyiby7jiiRMRESDeJXrdb4kNqyA3D3nVOt14bKgD/UiDfUKE1MwiV
pOqj/S0wiJdChKW52zRAkwuQ7PtKkgI=
=AiY9
-----END PGP MESSAGE-----
--11d2cbf164a9ae0dfbb310faf818762607dcfd20aa74e07c7be0eec1458d--
which is correct, and decodes correctly in neomutt.
Fixes: https://lists.sr.ht/~sircmpwn/sr.ht-discuss/%3C4uxbrlspm45s5i4bhhmqgmry374i22oqcxedtowda5zrzd7bpf2%405pyosds5owty%3E
email: remove content headers of passed-in message
The email has already been parsed according to the headers, but they are
still present. However, signing or encrypting the email will change the
content format, so remove any such headers before continuing.
email: handle error from Enqueue() in EnqueueStd()
email/worker: add more context to errors
For instance, failure to open the private PGP key would just fail
with an unhelpful "panic: open : no such file or directory" error.
email.EnqueueStd: Don't overwrite headers
Sometimes we need to specify the Message-Id, From, and Reply-To headers
(e.g. for todo.sr.ht ticket notifications). Don't overwrite these
headers if they are present.
email: handle failure to encrypt notifications
Currently, failure to encrypt the notification email - e.g. due to an
expired key - will make the entire request fail. Instead, fall back to
sending an unencrypted email and let the request succeed (unless that
fails also, which is unlikely).