-
Notifications
You must be signed in to change notification settings - Fork 85
Allow custom email server for invitations #796
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing I've commented on here requires changing. Feel free to address in a followup if necessary.
@@ -49,7 +49,8 @@ func (c *Controller) ensureFirebaseUserExists(ctx context.Context, user *databas | |||
} | |||
|
|||
if created { | |||
if err := c.firebaseInternal.SendNewUserInvitation(ctx, user.Email); err != nil { | |||
err := c.emailer.SendNewUserInvitation(ctx, user.Email) | |||
if err != nil { | |||
flash.Error("Could not send new user invitation: %v", err) | |||
return true, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dunno if we want to wrap errors. We're typically trying to.
pkg/email/config.go
Outdated
|
||
User string `env:"EMAIL_USER" json:",omitempty"` | ||
Password string `env:"EMAIL_PASSWORD" json:",omitempty"` | ||
SmtpHost string `env:"EMAIL_SMTP_HOST" json:",omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dunno why these are separate, especially when you just combine them later....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lines like smtp.PlainAuth("", s.User, s.Password, s.SmtpHost)
use the host alone, we add on the port only for the connection
pkg/email/smtp.go
Outdated
|
||
User string | ||
Password string | ||
SmtpHost string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
// Sending email. | ||
err = smtp.SendMail(s.SMTPHost+":"+s.SMTPPort, auth, s.User, []string{toEmail}, []byte(finalMessage)) | ||
if err != nil { | ||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrap, or don't bother setting err.
|
||
inviteLink, err := s.FirebaseAuth.PasswordResetLink(ctx, toEmail) | ||
if err != nil { | ||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrap
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bump
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: jeremyfaller, whaught The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
||
User string `env:"EMAIL_USER" json:",omitempty"` | ||
Password string `env:"EMAIL_PASSWORD" json:",omitempty"` | ||
SMTPHost string `env:"EMAIL_SMTP_HOST" json:",omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably worth noting that this won't work for most modern Gmail accounts, and won't work for G Suite Google Workplace either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait... but it does. I'm running [email protected] to test this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't have MFA enabled then? It won't work with advanced protection accounts either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://support.google.com/mail/answer/185833
With MFA you need to create an app password for this to use
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
App Passwords aren’t recommended and are unnecessary in most cases.
If you don’t have this option, it might be because:
c. Your account is through work, school, or other organization.
d. You turned on Advanced Protection.
c is very likely. d will probably become a default in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding in some notes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank
|
||
type Provider interface { | ||
// SendNewUserInvitation sends an invite to join the server. | ||
SendNewUserInvitation(ctx context.Context, email string) error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would probably be better to abstract the email content from the email sending. I'd expect the email provider to only know how to SendEmail
:
type Provider interface {
SendEmail(ctx context.Context, subject, to, cc, bcc string, body io.Reader)
}
func (s *SMTPProvider) SendNewUserInvitation(ctx context.Context, toEmail string) error { | ||
// Header | ||
header := make(map[string]string) | ||
header["From"] = s.User |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should try to make most of these constants. Both the map keys and many of their values are constant.
|
||
inviteLink, err := s.FirebaseAuth.PasswordResetLink(ctx, toEmail) | ||
if err != nil { | ||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bump
header["Subject"] = "COVID-19 Verification Server Invitation" | ||
|
||
header["MIME-Version"] = "1.0" | ||
header["Content-Type"] = `text/html; charset="utf-8"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we want to send as text/html. The firebase ones are text/plain.
Issue #787
Proposed Changes
In the future we can use this to
This gets around our server-side call to the firebase client API which may face IP rate limiting.
https://cloud.google.com/identity-platform/quotas#email_link_generation_limits_2
Note that generating the link has 10x quota and is intended to be called from the server.
We could someday send other kinds of emails (eg. TOTP for 2nd factor auth if we want to roll our own 2nd factor via this and Twilio), but that sort of thing is not currently planned.
Release Note