Commit Graph

17 Commits

Author SHA1 Message Date
Aaron Gable f5525ccd15
Parallelize notify-mailer (#6268)
Use the same pattern as was recently implemented in
expiration-mailer to parallelize notify-mailer. This should
significantly increase throughput when sending emails
to all subscribers.
2022-08-02 16:18:01 -07:00
Samantha ecd6d0118c
notify-mailer: Improve error checking during template execution (#5932)
- Break message body construction out into a testable method.
- Ensure that in the event of a missing key, an informative error is returned instead
  of allowing the message to be populated with the zero value of the key.
- Add message body construction tests for success, empty map, and missing key. 
- Comment the `recipient` struct and it's `Data` field to make it clear that SRE
  must be informed of any modifications.

Fixes #5921
2022-02-08 09:53:51 -08:00
Aaron Gable 305ef9cce9
Improve error checking paradigm (#5920)
We have decided that we don't like the if err := call(); err != nil
syntax, because it creates confusing scopes, but we have not cleaned up
all existing instances of that syntax. However, we have now found a
case where that syntax enables a bug: It caused readers to believe that
a later err = call() statement was assigning to an already-declared err
in the local scope, when in fact it was assigning to an
already-declared err in the parent scope of a closure. This caused our
ineffassign and staticcheck linters to be unable to analyze the
lifetime of the err variable, and so they did not complain when we
never checked the actual value of that error.

This change standardizes on the two-line error checking syntax
everywhere, so that we can more easily ensure that our linters are
correctly analyzing all error assignments.
2022-02-01 14:42:43 -07:00
Jacob Hoffman-Andrews 23dd1e21f9
Build all boulder binaries into a single binary (#5693)
The resulting `boulder` binary can be invoked by different names to
trigger the behavior of the relevant subcommand. For instance, symlinking
and invoking as `boulder-ca` acts as the CA. Symlinking and invoking as
`boulder-va` acts as the VA.

This reduces the .deb file size from about 200MB to about 20MB.

This works by creating a registry that maps subcommand names to `main`
functions. Each subcommand registers itself in an `init()` function. The
monolithic `boulder` binary then checks what name it was invoked with
(`os.Args[0]`), looks it up in the registry, and invokes the appropriate
`main`. To avoid conflicts, all of the old `package main` are replaced
with `package notmain`.

To get the list of registered subcommands, run `boulder --list`. This
is used when symlinking all the variants into place, to ensure the set
of symlinked names matches the entries in the registry.

Fixes #5692
2021-10-20 17:05:45 -07:00
Samantha d08668f8ad
notify-mailer: Improve recipient list parser (#5495)
- Parse recipient list file as a TSV when flag `-tsv` is provided
- Log recipient list records that contain empty columns
- Log and skip recipient list records that contain the same `id` as previously
  read records
- Remove unnecessary check for mismatched header and record column length, this
  is already handled by the `encoding/csv` package
- Remove unnecessary check for empty line, this is already handled by the
  `encoding/csv` package

Part of  #5420
2021-06-28 16:45:22 -07:00
Samantha 205223abbc
notify-mailer: Improve terminology consistency and general cleanup (#5485)
### Improve consistency
- Make registration `id` an `int64`
- Use `address`, `recipient`, and `record` terminology
- Use `errors.New()` in place of `fmt.Errorf()`
- Use `strings.Builder` in place of `bytes.Buffer`
- Use `errors.Is()` when checking for sentinel errors
- Remove unused (duplicate) `cmd.PasswordFile` in `config`
- Remove unused `cmd.Features` in `config`

### Improve readability
- Use godoc standard comments
- Replace multiple calls to `len(someVariable)` with `totalSomeVariable`

Part of #5420
2021-06-15 10:09:19 -07:00
Jacob Hoffman-Andrews 6f4966cc0f
Check email address validity in notify-mailer. (#4841)
This required a refactoring: Move validateEmail from the RA to ValidEmail
in the `policy` package. I also moved `ValidDomain` from a method on
PolicyAuthority to a standalone function so that ValidEmail can call it.

notify-mailer will now log invalid addresses and skip them without
attempting to send mail. Since @example.com addresses are invalid,
I updated the notify-mailer test, which used a lot of such addresses.

Also, now when notify-mailer receives an unrecoverable error sending
mail, it logs the email address and what offset within the list it was.
2020-06-04 18:28:02 -07:00
Jacob Hoffman-Andrews bef02e782a
Fix nits found by staticcheck (#4726)
Part of #4700
2020-03-30 10:20:20 -07:00
Daniel McCarney 1c9ece3f44
SA: use wrapped database maps/transactions. (#4585)
New types and related infrastructure are added to the `db` package to allow
wrapping gorp DbMaps and Transactions.

The wrapped versions return a special `db.ErrDatabaseOp` error type when errors
occur. The new error type includes additional information such as the operation
that failed and the related table.

Where possible we determine the table based on the types of the gorp function
arguments. Where that isn't possible (e.g. with raw SQL queries) we try to use
a simple regexp approach to find the table name. This isn't great for general
SQL but works well enough for Boulder's existing SQL queries.

To get additional confidence my regexps work for all of Boulder's queries
I temporarily changed the `db` package's `tableFromQuery` function to panic if
the table couldn't be determined. I re-ran the full unit and integration test
suites with this configuration and saw no panics.

Resolves https://github.com/letsencrypt/boulder/issues/4559
2019-12-04 13:03:09 -05:00
Jacob Hoffman-Andrews 4b9fd1f97e notify-mailer: Support CSV and parameters (#4024)
Fixes #4018 

This rearranges notify-mailer so we can give it CSV input and interpolate fields from that CSV.
It removes the old-style JSON input so we don't have to support two different input styles.

When multiple accounts have the same email address, their recipient data is consolidated under
that address so they only receive a single email. The CSV data can be interpolated using
the `range` operator in Golang templates.

Because we're now operating on the resolved email addresses instead of purely on accounts,
this PR also changes the checkpointing mode. Instead of a numeric start and end, it takes
a pair of strings, and only sends to email addresses between those two strings.
2019-01-22 16:07:17 -08:00
Daniel McCarney ed01d6bc14 notify-mailer: skip invalid contact emails (#4021)
Resolves #4020
2019-01-18 11:47:21 -08:00
Jacob Hoffman-Andrews 281e2546f3
De-duplicate email addresses in notify-mailer. (#4015)
Resolves #4003
2019-01-17 11:34:04 -08:00
Daniel bcc389d109
Fixes gofmt -s diffs 2016-11-30 13:30:03 -05:00
Daniel McCarney b824f31a4c `notify-mailer` graceful handling of `sql.ErrNoRows`. (#2185)
* Fixes `mockEmailResolver` to return `sql.ErrNoRows`.

This commit reproduces the error observed in #2183 where a registration
ID is provided that doesn't match a row with a valid contact.

First a bug is fixed in the ID range check done by the
`mockEmailResolver` - it was using a `||` where it should have been
using a `&&` and also had a `> 0` where it needed `>= 0`, oops! slipped
past review!

Second the `mockEmailResolver` is modified to return `sql.ErrNoRows`
when the index is out of bounds for the mock data.

Lastly a ID of `999` is added to the `TestResolveEmails` function to
elicit the "mailer.send returned error: sql: no rows in result set"
error.

* Handles `sql.ErrNoRows` in `emailsForReg`.

This commit fixes #2183 (and the failing unit test introduced in the
prior commit) by handling `sql.ErrNoRows` in `emailsForReg` gracefully.

* Clarfies mockEmailResolver comment
2016-09-19 12:14:48 -07:00
Daniel McCarney b16585be5d `notify-mailer` monitor progress (#2046)
This PR adds a `printStatus` function that is called every iteration of the mailer's `run()` loop. The status output is logged at the `info` level and includes the destination email, the current message being sent, the total number of messages to send, and the elapsed time since `run()` started.

The status output can be disabled by lowering the default syslog level in the `notify-mailer` config.

Additionally, this PR adds stats support for the mailer package. Three new stats are
published during the `MailerImpl`'s `SendMail` function (called in a loop by the mailer utilities):
  `Mailer.SendMail.Attempts`
  `Mailer.SendMail.Successes`
  `Mailer.SendMail.Errors`

This PR removes two stats from the `expiration-mailer` that are redundant copies of the above:
  `Mailer.Expiration.Errors.SendingNag.SendFailure`
  `Mailer.Expiration.Sent`

This resolves #2026.
2016-07-26 11:26:08 -04:00
Daniel McCarney 217b79b8c2 Support Reg ID intermediate form for notify mails (#1958)
Presently the `contact-exporter` dumps a list of email addresses to an intermediate file. That file can be provided as input to `notify-mailer` to send messages to the listed email addresses. This has the downside that if a user updates their registration contact address between the time the export is run and the notification emails are sent the message will go to the wrong address.

This PR addresses this by adding a new default output mode to the `contact-exporter` that writes JSON serialized objects containing both a registration ID and an email address to an intermediate file. The `notify-mailer` is updated to support reading this file, deserializing the JSON, and resolving the reg IDs to fresh email addresses before sending messages.

The "classic" behaviour of using bare email addresses as the intermediate form is supported with both the `contact-exporter` and the `notify-mailer` by providing the `--emails` bool flag at the command line.

Resolves #1951
2016-07-12 16:01:38 -07:00
Daniel McCarney 6bd97b2a6b Adds `notify-mailer` command. (#1936)
This commit adds a new notify-mailer command. Outside of the new command, this PR also:

Adds a new SMTPConfig to cmd/config.go that is shared between the expiration mailer and the notify mailer.
Modifies mail/mailer.go to add an smtpClient interface.
Adds a dryRunClient to mail/mailer.go that implements the smtpClient interface.
Modifies the mail/mailer.go MailerImpl and constructor to use the SMTPConfig and a dialer. The missing functions from the smtpClient interface are added.
The notify-mailer command supports checkpointing through --start and --end parameters. It supports dry runs by using the new dryRunClient from the mail package when given the --dryRun flag. The speed at which emails are sent can be tweaked using the --sleep flag.

Unit tests for notify-mailer's checkpointing behaviour, the checkpoint interval/sleep parameter sanity, the sleep behaviour, and the message content construction are included in main_test.go.

Future work:

A separate command to generate the list of destination emails provided to notify-mailer
Support for using registration IDs as input and resolving the email address at runtime.
Resolves #1928. Credit to @jsha for the initial work - I'm just completing the branch he started.

* Adds `notify-mailer` command.
* Adds a new SMTPConfig to `cmd/config.go` that is shared between the
expiration mailer and the notify mailer.
* Modifies `mail/mailer.go` to add an `smtpClient` interface.
* Adds a `dryRunClient` to `mail/mailer.go` that implements the
  `smtpClient` interface.
* Modifies the `mail/mailer.go` `MailerImpl` and constructor to use the
  SMTPConfig and a dialer. The missing functions from the `smtpClient`
  interface are added.
* Fix errcheck warnings
* Review feedback
* Review feedback pt2
* Fixes #1446 - invalid message-id generation.
* Change -configFile to -config
* Test message ID with friendly email

https://github.com/letsencrypt/boulder/pull/1936
2016-06-16 15:12:31 -07:00