Sending Email with Dark
In my last post on Dark, I created a self-destructing message app that lets you share a secret, like a password, with someone by sharing a link. When they view the message it will be deleted on the server. A nice feature would be to notify the sender via email when their message was viewed.
To start, we will modify the React client to pass the email address to the backend:
const response = await fetch(BASE_API + '/upload', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({text: cipherText, email}),
});
Then we can submit the form, now including an email, to
create a trace in Dark. Recall from our last post that we
have a Datastore named Messages
, that has two fields,
text
and createdAt
. In order to add a new field, we will
need to clear the Datastore:
DB::deleteAllv1 Messages
Then we can add a new field email
of type String
. Next,
as we process the message upload, we will include the
email
in the call to DB::set
:
let text = request.body.text
if String::lengthv1 text > 1024
then
Http::badRequest "Text too long: text is limited to 256 ch
aracters"
else
let key = DB::generateKey
let _ = DB::setv1
{
text : text
createdAt : Date::now
email : request.body.email
}
key
Messages
{
id : key
}
Finally we get to the part where we actually send an email.
I used (sendinblue)[https://www.sendinblue.com/] because
they have a generous free tier and good docs with an easy to
use API. Once you've signed up, create a new Secret Key in
Dark by clicking the +
next to "Secret Keys". Call it
SENDINBLUE_API
and paste in your API key.
Then we'll create a function in Dark to keep the /download
handler concise. Click the +
next to "Functions" and call
it emailMessageViewed
. We will setup this function with
one paramter email
of type String
.
In the body we will use sendinblue's REST API to send a confirmation email:
HttpClient::postv5
"https://api.sendinblue.com/v3/smtp/email"
{
sender : {
name : "Secure Message"
email : "noreply@ianobermiller.com"
}
to : [{
email : email
}]
subject : "Secure Message Viewed"
htmlContent : "<html><head></head><body><p>Your secure
message has been viewed and deleted.</p>
<p><a href="https://ianobermiller.com/se
cure">Create a new message</a></p></body
></html>"
}
{}
{
api-key : SENDINBLUE_API
}
This is quite straightforward since Dark provides good
helpers for making HTTP calls. In this case we use the
sendinblue API endpoint
https://api.sendinblue.com/v3/smtp/email
, pass in a JSON
blob with the sender
, to
, subject
, and htmlContent
,
and finally set the api-key
header to our Secret Key named
SENDINBLUE_API
.
Finally, let's call this new function from our `/download' handlers:
let entry = DB::getv2 request.body.id Messages
let _ = DB::deletev1 request.body.id Messages
let _ = if entry.email
then
emailMessageViewed entry.email
else
Nothing
{
text : entry.text
}
Since the email is optional, we want to verify it is non-empty before trying to send a confirmation. And that's all there is to it!