Incoming email hooks and you!
Monday, November 11, 2019
Sometimes when you are making your cool app thing you want to accept email. This could be for a myriad of reasons.
Consider the Github use case. When someone comments on an issue you are watching you will receive an email. If you reply to the email it adds a comment to the issue!
Let’s learn about some cool email headers and how we might go about building that ourselves.
I’ll be using Postmark as the email sender/receiver. Most other email services like them also have this functionality. I just think they are cool and use them for my own projects.
Setup
I’m going to skip a bit past the initial steps of creating an account and a server. Postmark has that well documented.
What we care about is the incoming email hook.
First we go to default inbound stream.
Then in the settings tab the inbound email hook
We’ll also want to set an inbound email domain. You’ll have to look up How to set that up in your DNS
Okay so we have our quick setup. Postmark has great docs so check those out for more setup info. Though to note it’s very important to have a custom inbound domain to accomplish what we want to do!
Sending our email
Let’s send our email to the user. What do we want to track how we will know it is them?
Message-ID
Message-ID
-
<42.0B.41170.86A79BB5@twitter.com>
Message-ID
-
<42.0B.41170.86A79BB5@twitter.com>
Message-ID
-
<42.0B.41170.86A79BB5@twitter.com>
Message-ID
-
<42.0B.41170.86A79BB5@twitter.com>
Message-ID
-
<42.0B.41170.86A79BB5@twitter.com>
Message-ID
-
<42.0B.41170.86A79BB5@twitter.com>
170.86A79BB5@twitter.com>`
In-Reply-To
This email header is the starting point for how email clients thread emails. When you reply to an email your client puts the
Message-ID
of the email sent to you in the
In-Reply-To
header
References
This header contains the
Message-ID
s of all the emails in the email thread. Every time a new email is send in a thread the
Message-ID
of the email being replied to is also appened to the
References
field
Reply-To
When you send an email you can set a reply to address that differs from the to address you sent the email from. These headers are going to enable our workflow.
So let’s send our email.
// Require:
const postmark = require("postmark");
// Send an email:
const client = new postmark.Client("POSTMARK-SERVER-API-TOKEN-HERE");
const emailId = await generateAndStoreNewEmailId(commentThread, user);
client.sendEmail({
"From": "sender@example.com",
"To": "recipient@example.com",
"Reply-To": `
inbound+${emailId}@inbound.ourdomain.com
`
"Subject": "Test",
"TextBody": "Hello from Postmark!",
"Headers": [{Name: "Message-ID", Value: `
<${emailId}@inbound.ourdomain.com>
`}]
});
Okay so notice we set our Reply-To to an inbound email with an id we generated. We also want to store the user we are sending this email to and what comment thread.
Now we wait for a reply
Handling the inbound email
When any email is sent to our inbound email domain we will get a post request to our webhook. The entire message is quite big you can see it here. We just care about a few fields. We will use them to lookup the context for this email and add the comment.
The reason we used the
inbound+${emailId}
in our
Reply-To
was because postmark is nice enough to parse that id off for us and add it to a field called
MailboxHash
.
Now we can lookup the thread this email is talking about from the emailId.
const emailInfo = await getEmailInfo(inboundEmail.MailboxHash)
Postmark is also nice enough to parse the email body and give us just the reply text. We will use that for the commend body!
const body = inboundEmail.TextBody;
Then we can do something.
await createCommentInThread(
emailInfo.commentThreadId,
emailInfo.user,
body
)
Conclusion
We also stored the email id in the
Message-ID
so if for some reason we can’t find our comment thread via
Reply-To
we can search the
References
or
In-Reply-To
fields to check as well.
This is the general strategy that GitLab uses
This was a pretty high level overview but hopefully it helps you understand how easy it can be to make your app accept incoming emails!