Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notify-mailer: save and reuse resolved email addresses #7979

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

lenaunderwood22
Copy link
Contributor

@lenaunderwood22 lenaunderwood22 commented Jan 24, 2025

Add saveEmailsTo and readEmailsFrom optionals flags to notify-mailer to enable saving and reusing work to resolve email addresses.

  • The saveEmailsTo is the filename of where to save resolved address/recipient data
  • The readEmailsFrom is the filename of where to read resolved address/recipient data.

New use cases:

  1. Save resolved address/recipient data for reuse: Set the saveEmailsTo flag and notify-mailer will run and save resolved address/recipient data to the specified file.
  2. Use previously saved address/recipient data to send emails: Set the readEmailsFrom flag and notify-mailer will extract the saved recipient data to send emails, instead of redoing the work to resolve addresses.
  3. Send emails in batches: Set both the readEmailsFrom and saveEmailsTo flags. Notify-mailer will read the addresses in readEmailsFrom and then resolve addresses from the input recipients file if the address is NOT in readEmailsFrom. After resolving and sending to the new recipients, the combined set of addresses sent by the current run and seen in readEmailsFrom are saved to the saveEmailsTo file.

Important Note: doing a batch send (case 3) WILL NOT WORK entirely correctly if the email body includes recipient-specific data (e.g. embedding recipient's certificate domain names). Only use both saveEmailsTo and readEmailsFrom flags if email body is exactly the same regardless of recipient.

@lenaunderwood22 lenaunderwood22 marked this pull request as ready for review January 28, 2025 17:04
@lenaunderwood22 lenaunderwood22 requested a review from a team as a code owner January 28, 2025 17:04
Copy link
Contributor

@aarongable aarongable left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New flags LGTM. Just a couple tiny comments about comments, and one big piece of feedback about how we use the data from the loaded file to actually save ourselves time.

Comment on lines +132 to +133
err = os.WriteFile(filename, jsonData, 0644)
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
err = os.WriteFile(filename, jsonData, 0644)
return err
return os.WriteFile(filename, jsonData, 0644)

@@ -153,6 +166,16 @@ func (m *mailer) run(ctx context.Context) error {
m.log.Infof("Address %q was associated with the most recipients (%d)",
mostRecipients, mostRecipientsLen)

// If saveEmailsTo set but readEmailsFrom not, write the map of resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// If saveEmailsTo set but readEmailsFrom not, write the map of resolved
// If saveEmailsTo is set but readEmailsFrom is not, write the map of resolved

Comment on lines +278 to +280
// `recipient`s that resolve to that email address. If readEmailsMap isn't nil:
// a) if saveEmailsTo unset, then return readinsteadEmailsMap
// b) otherwise, resolve addresses that aren't in readEmailsMap
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// `recipient`s that resolve to that email address. If readEmailsMap isn't nil:
// a) if saveEmailsTo unset, then return readinsteadEmailsMap
// b) otherwise, resolve addresses that aren't in readEmailsMap
// `recipient`s that resolve to that email address. If readEmailsMap is
// populated and we're not saving emails into saveEmailsTo, just return
// the loaded map.

{"Data":{"date":"2018-11-21","domainName":"example.com"}},
{"Data":{"date":"2018-11-22","domainName":"example.net"}}
]
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file doesn't have a terminating newline character.

[
{"Data":{"date":"2018-11-21"}}
]
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file doesn't have a terminating newline character.

Comment on lines +298 to +300
if _, ok := m.readEmailsMap[parsed.Address]; !ok {
result[parsed.Address] = append(result[parsed.Address], recipient)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. So while the end result here is what we want -- only updating the map for addresses that we haven't already processed -- this stanza is too late to save us from actually doing extra work. We're still doing all of the database lookups for every recipient, we're just dropping the result on the floor if it turns out we've looked this one up before.

I think this needs to happen earlier. When we read the emails map from disk, we should also keep track of every regID seen in that map. And then we can add something like

_, present := m.cachedRecipients[recipient.id]
if present {
  continue
}

between lines 286 and 287 of this function, to actually save ourselves work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants