diff --git a/package-lock.json b/package-lock.json
index a4236d0..178a41d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -887,6 +887,15 @@
}
}
},
+ "@types/nodemailer": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.0.tgz",
+ "integrity": "sha512-KY7bFWB0MahRZvVW4CuW83qcCDny59pJJ0MQ5ifvfcjNwPlIT0vW4uARO4u1gtkYnWdhSvURegecY/tzcukJcA==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/prop-types": {
"version": "15.7.3",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
@@ -928,6 +937,16 @@
"@types/mime": "*"
}
},
+ "@types/smtp-server": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/@types/smtp-server/-/smtp-server-3.5.3.tgz",
+ "integrity": "sha512-15g2q1C2F3iiVOQlEjChndNb9wAZZiNBLIO0Xg4+JGc9FvdiD1p6DaLVkbU1I8eHd0g624xz0ateamo3nY0ENw==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "@types/nodemailer": "*"
+ }
+ },
"@types/stack-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
@@ -1320,6 +1339,11 @@
}
}
},
+ "base32.js": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz",
+ "integrity": "sha1-tYLexpPC8R6JPPBk7mrFthMaIgI="
+ },
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
@@ -2866,6 +2890,11 @@
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
},
+ "ipv6-normalize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ipv6-normalize/-/ipv6-normalize-1.0.1.tgz",
+ "integrity": "sha1-GzJYKQ02X6gyOeiZB93kWS52IKg="
+ },
"is-accessor-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
@@ -4924,6 +4953,11 @@
}
}
},
+ "nodemailer": {
+ "version": "6.4.5",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.5.tgz",
+ "integrity": "sha512-NH7aNVQyZLAvGr2+EOto7znvz+qJ02Cb/xpou98ApUt5tEAUSVUxhvHvgV/8I5dhjKTYqUw0nasoKzLNBJKrDQ=="
+ },
"nodemon": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.2.tgz",
@@ -6051,6 +6085,16 @@
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
+ "smtp-server": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/smtp-server/-/smtp-server-3.6.0.tgz",
+ "integrity": "sha512-DVEVWzL4s1GWzAs4+6rbhNZpAn61+V8l4b7R8zHLAW2jmlwKz9IKQmdgm5sNruCRnS01BYyitI98vJo7LDnXfg==",
+ "requires": {
+ "base32.js": "0.1.0",
+ "ipv6-normalize": "1.0.1",
+ "nodemailer": "6.4.5"
+ }
+ },
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
diff --git a/package.json b/package.json
index 7ebecc8..12b7a30 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,7 @@
"express": "^4.17.1",
"react": "^16.13.0",
"react-dom": "^16.13.0",
+ "smtp-server": "^3.6.0",
"xml2js": "^0.4.23"
},
"devDependencies": {
@@ -17,6 +18,7 @@
"@types/node-fetch": "^2.5.5",
"@types/react": "^16.9.23",
"@types/react-dom": "^16.9.5",
+ "@types/smtp-server": "^3.5.3",
"@types/xml2js": "^0.4.5",
"concurrently": "^5.1.0",
"jest": "^25.1.0",
diff --git a/src/index.tsx b/src/index.tsx
index 275a9ca..954aabf 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,5 +1,6 @@
import express from "express";
import { Server } from "http";
+import { SMTPServer } from "smtp-server";
import React from "react";
import ReactDOMServer from "react-dom/server";
import { Builder } from "xml2js";
@@ -11,7 +12,7 @@ const webApp = express()
.use(express.urlencoded({ extended: true }))
.get("/", (req, res) =>
res.send(
- renderHtml(
+ renderHTML(
Subscribe to the Atom feed at
- {feedUrl(token)}
+ {feedURL(token)}
Don’t share these addresses. @@ -176,7 +181,7 @@ function Feed(inbox: Inbox) { $: { rel: "self", type: "application/atom+xml", - href: feedUrl(token) + href: feedURL(token) } }, { @@ -237,7 +242,7 @@ export function feedPath(token: string) { return `static/feeds/${token}.xml`; } -function feedUrl(token: string) { +function feedURL(token: string) { return `https://www.kill-the-newsletter.com/feeds/${token}.xml`; } @@ -249,10 +254,10 @@ function id(token: string) { return `urn:kill-the-newsletter:${token}`; } -function renderHtml(component: React.ReactElement): string { +function renderHTML(component: React.ReactElement): string { return `\n${ReactDOMServer.renderToStaticMarkup(component)}`; } -function renderXml(xml: object): string { +function renderXML(xml: object): string { return new Builder().buildObject(xml); } diff --git a/src/test.ts b/src/test.ts index 2095ee5..b99982e 100644 --- a/src/test.ts +++ b/src/test.ts @@ -1,4 +1,4 @@ -import { developmentWebServer, feedPath } from "."; +import { developmentWebServer, emailServer, feedPath } from "."; import fetch from "node-fetch"; import fs from "fs"; @@ -16,4 +16,5 @@ test("create feed", async () => { afterAll(() => { developmentWebServer.close(); + emailServer.close(() => {}); });