Skip to content

Commit

Permalink
feat: Add email sending feature
Browse files Browse the repository at this point in the history
  • Loading branch information
clemfromspace committed Jul 20, 2021
1 parent 3f86fa6 commit 10b0ad5
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 11 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@ ALGOLIA_INDEX_NAME=

ALGOLIA_RECOMMENDATION_API_KEY=

SENDGRID_API_KEY=
SENDGRID_FROM_EMAIL=

# Envs
STATIC_DIR=../../client
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,19 @@ ALGOLIA_INDEX_NAME=<replace-with-your-algolia-index-name>
ALGOLIA_API_KEY=<replace-with-your-algolia-api-key>
```

### 6. Follow the instructions in the server directory
### 4. (Optional) Configure an email sending provider

The sample application allow you to send the preview to your email address using an email sending provider.
We do provide a minimal working exemple with [SendGrid](https://sendgrid.com/).

In order to use SendGrid, you need to set the environment variables `SENDGRID_API_KEY` and `SENDGRID_FROM_EMAIL` in the `.env` file:

```bash
SENDGRID_API_KEY=<replace-with-your-sendgrid-api-key>
SENDGRID_FROM_EMAIL=<replace-with-sendgrid-from-email>
```

### 5. Follow the instructions in the server directory

Each server directory has a file with instructions:

Expand Down
6 changes: 6 additions & 0 deletions client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
<select name="templateName" id="templateName"></select>
</form>
<p id="explanation"></p>
<hr>
<form action="" id="sendForm">
<label for="toEmail">Send this email</label>
<input type="email" name="toEmail" id="toEmail" required/>
<button type="submit">Send</button>
</form>
</div>
<div id="main"></div>
</div>
Expand Down
17 changes: 17 additions & 0 deletions client/js/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var selectTemplateEl = document.getElementById("templateName");
var sendEmailFormEl = document.getElementById("sendForm");

selectTemplateEl.addEventListener("change", function(ev) {
var emailIndex = ev.target.value;
Expand Down Expand Up @@ -31,3 +32,19 @@ var loadTemplates = function() {

loadTemplates();

sendEmailFormEl.addEventListener("submit", function(ev) {
ev.preventDefault();
var emailInputEl = document.getElementById("toEmail");
var selectTemplateEl = document.getElementById("templateName");
var sendUrl = "/send/" + selectTemplateEl.value;
fetch(sendUrl, {
method: 'POST',
body: JSON.stringify({
toEmail: emailInputEl.value,
}),
headers: {
'Content-type': 'application/json; charset=UTF-8'
}
}).then();
});

1 change: 1 addition & 0 deletions server/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"dependencies": {
"@algolia/recommend": "^4.10.2",
"@algolia/recommend-js": "^1.0.0",
"@sendgrid/mail": "^7.4.5",
"algoliasearch": "^4.9.1",
"body-parser": "^1.19.0",
"dotenv": "^8.0.0",
Expand Down
12 changes: 12 additions & 0 deletions server/node/sendgrid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Send a mail using the Sendgrid API
// https://www.npmjs.com/package/@sendgrid/mail

import sendgrid from "@sendgrid/mail";

const sendMail = async (to, subject, text, html) => {
const msg = {to, subject, text, html, from: process.env.SENDGRID_FROM_EMAIL,
};
await sendgrid.send(msg);
};

export default sendMail;
43 changes: 33 additions & 10 deletions server/node/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ import fs from "fs";
import { fileURLToPath } from "url";
import path from "path";

import bodyParser from "body-parser";
import dotenv from "dotenv"
import express from "express";
import nunjucks from "nunjucks";
import showdown from "showdown";
import sendgrid from "@sendgrid/mail";

import algoliaearch from "algoliasearch";
import algoliarecommend from "@algolia/recommend";

import sendEmail from "./sendgrid.js";

// Load env variables
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
Expand All @@ -25,6 +27,9 @@ const algoliaClient = algoliaearch(process.env.ALGOLIA_APP_ID, process.env.ALGOL
const recommendClient = algoliarecommend(process.env.ALGOLIA_APP_ID, process.env.ALGOLIA_API_KEY);
const algoliaIndex = algoliaClient.initIndex(process.env.ALGOLIA_INDEX_NAME);

// Setup email delivery
sendgrid.setApiKey(process.env.SENDGRID_API_KEY);

// Email templates rendering engine
// https://mozilla.github.io/nunjucks/
nunjucks.configure('templates', {
Expand All @@ -33,7 +38,7 @@ nunjucks.configure('templates', {
});

app.use(express.static(process.env.STATIC_DIR));
app.use(bodyParser.json())
app.use(express.json());

const loadEmails = async () => {
const EmailBaseDir = "./emails";
Expand All @@ -52,6 +57,17 @@ const loadEmails = async () => {
return emails;
};

const renderEmail = async (email) => {
// Load all products recommendations to populate the email template.
const recommendations = await Promise.all(
email.recommendations.map(f => f(algoliaIndex, recommendClient))
);
return nunjucks.render(email.template, {
...email,
recommendations: recommendations,
});
}


// Home page
app.get("/", (req, res) => {
Expand All @@ -76,18 +92,25 @@ app.get("/render/:emailIndex", async (req, res) => {
const { emailIndex } = req.params;
const emails = await loadEmails();
const email = emails[emailIndex];
const renderedEmail = await renderEmail(email);

// Load all products recommendations to populate the email template.
const recommendations = await Promise.all(
email.recommendations.map(f => f(algoliaIndex, recommendClient))
);
res.json({
'explanation': email.explanation,
'html': nunjucks.render(email.template, {
...email,
recommendations: recommendations,
})
'html': renderedEmail
});
});

// Send a given email, identified by his index
app.post("/send/:emailIndex", async (req, res) => {
const { emailIndex } = req.params;
const emails = await loadEmails();
const email = emails[emailIndex];
const renderedEmail = await renderEmail(email);

const { toEmail } = req.body;
await sendEmail(toEmail, email.title, "test", renderedEmail);

res.status(200);
});

app.listen(4242, () => console.log(`Node server listening on port ${4242}!`));

0 comments on commit 10b0ad5

Please sign in to comment.