Skip to content
Sameer Ismail edited this page Feb 9, 2022 · 1 revision

Email

Looking at the last email I received from LessWrong, it was from no-reply@lesserwrong.com and mailed by mg.lesserwrong.com. Looking at the MX records for this subdomain,

~ dig @1.1.1.1 MX mg.lesserwrong.com

; <<>> DiG 9.10.6 <<>> @1.1.1.1 MX mg.lesserwrong.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 57629
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;mg.lesserwrong.com.            IN      MX

;; ANSWER SECTION:
mg.lesserwrong.com.     300     IN      MX      10 mxa.mailgun.org.

;; Query time: 445 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: Wed Feb 09 21:07:44 AEDT 2022
;; MSG SIZE  rcvd: 78

we see that the Mailgun is the mail server provider.

Looking at the code, the core email handling module is sendEmail.ts (located in packages/lesswrong/server/emails). This gets the SMTP URL from the in-database server-only settings (see this for more on settings), and uses plain SMTP to send emails (not the Mailgun API). With nodemailer handling the SMTP peculiarities.

Then the sendEmail.ts::sendEmailSmtp function is called by renderEmail.tsx:sendEmail, and is wrapped by renderEmail.tsx:wrapAndSendEmail for custom HTML rendering. This is what is actually used in the event hooks, e.g. on signup:

const verifyEmailLink = await VerifyEmailToken.generateLink(user._id);
await wrapAndSendEmail({
  user, 
  subject: `Verify your ${forumTitleSetting.get()} email`,
  body: <div>
    <p>
      Click here to verify your {forumTitleSetting.get()} email
    </p>
    <p>
      <a href={verifyEmailLink}>
       {verifyEmailLink}
      </a>
    </p>
  </div>
})

For our implementation, instead of using in-DB credentials I propose continuing with the method used for the MongoDB connection string: environment variables injected at deploy time. (See the docker-compose.yml and GH actions in the deployment repository.)

This will look something like the following (with proper error handling, etc.):

const transport = nodemailer.createTransport({
  host: "smtp.mailgun.org",
  port: 587,
  secure: false,
  auth: {
    user: process.env.EMAIL_USER,
    pass: process.env.EMAIL_PASSWORD,
  }
});

Clone this wiki locally