@netlify/plugin-emails
Advanced tools
Comparing version 0.4.6-preview to 1.0.0
@@ -6,7 +6,2 @@ import { Handler } from "@netlify/functions"; | ||
} | undefined; | ||
interface IAttachment { | ||
content: string; | ||
filename: string; | ||
type: string; | ||
} | ||
export interface IEmailRequest { | ||
@@ -19,3 +14,2 @@ from: string; | ||
bcc?: string; | ||
attachments?: IAttachment[]; | ||
} | ||
@@ -32,19 +26,3 @@ interface IEmailConfig { | ||
} | ||
export interface IMissingConfig { | ||
NETLIFY_EMAILS_SECRET?: boolean; | ||
NETLIFY_EMAILS_PROVIDER?: boolean; | ||
NETLIFY_EMAILS_PROVIDER_API_KEY?: boolean; | ||
NETLIFY_EMAILS_MAILGUN_HOST_REGION?: boolean; | ||
NETLIFY_EMAILS_MAILGUN_DOMAIN?: boolean; | ||
} | ||
export interface IRenderRequest { | ||
template: string; | ||
siteId: string; | ||
type: string; | ||
showParameterDictionary: boolean; | ||
parameters: { | ||
[key: string]: string | string[]; | ||
}; | ||
} | ||
declare const handler: Handler; | ||
export { handler }; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
@@ -18,3 +41,2 @@ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
const path_1 = require("path"); | ||
const https_1 = __importDefault(require("https")); | ||
const getEmailFromPath = (path) => { | ||
@@ -40,103 +62,24 @@ let fileFound; | ||
const allowedPreviewEnvironments = ["deploy-preview", "branch-deploy", "dev"]; | ||
const getMissingConfig = () => { | ||
var _a; | ||
const missingConfig = {}; | ||
let validConfig = true; | ||
if (!process.env.NETLIFY_EMAILS_PROVIDER) { | ||
missingConfig.NETLIFY_EMAILS_PROVIDER = true; | ||
validConfig = false; | ||
const isConfigValid = () => { | ||
if (process.env.NETLIFY_EMAILS_PROVIDER_API_KEY === undefined) { | ||
return false; | ||
} | ||
if (!process.env.NETLIFY_EMAILS_PROVIDER_API_KEY) { | ||
missingConfig.NETLIFY_EMAILS_PROVIDER_API_KEY = true; | ||
validConfig = false; | ||
if (process.env.NETLIFY_EMAILS_PROVIDER === undefined) { | ||
return false; | ||
} | ||
if (((_a = process.env.NETLIFY_EMAILS_PROVIDER) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === "mailgun") { | ||
if (!process.env.NETLIFY_EMAILS_MAILGUN_HOST_REGION) { | ||
missingConfig.NETLIFY_EMAILS_MAILGUN_HOST_REGION = true; | ||
validConfig = false; | ||
if (process.env.NETLIFY_EMAILS_PROVIDER === "mailgun") { | ||
if (process.env.NETLIFY_EMAILS_MAILGUN_DOMAIN === undefined) { | ||
return false; | ||
} | ||
if (!process.env.NETLIFY_EMAILS_MAILGUN_DOMAIN) { | ||
missingConfig.NETLIFY_EMAILS_MAILGUN_DOMAIN = true; | ||
validConfig = false; | ||
if (process.env.NETLIFY_EMAILS_MAILGUN_HOST_REGION === undefined) { | ||
return false; | ||
} | ||
} | ||
if (!process.env.NETLIFY_EMAILS_SECRET) { | ||
missingConfig.NETLIFY_EMAILS_SECRET = true; | ||
validConfig = false; | ||
} | ||
return validConfig ? false : missingConfig; | ||
return true; | ||
}; | ||
const makeRenderTemplateRequest = (fileFound, parameters) => __awaiter(void 0, void 0, void 0, function* () { | ||
const renderRequest = { | ||
template: fileFound.file, | ||
siteId: process.env.SITE_ID, | ||
type: fileFound.type, | ||
showParameterDictionary: false, | ||
parameters, | ||
}; | ||
return yield new Promise((resolve, reject) => { | ||
const renderReq = https_1.default.request({ | ||
hostname: "netlify-integration-emails.netlify.app", | ||
path: "/.netlify/functions/render", | ||
method: "POST", | ||
headers: { | ||
"site-id": process.env.SITE_ID, | ||
"Content-Type": "application/json", | ||
}, | ||
}, (res) => { | ||
let data = ""; | ||
res.on("data", (chunk) => { | ||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands | ||
data += chunk; | ||
}); | ||
res.on("end", () => { | ||
var _a; | ||
const response = JSON.parse(data); | ||
resolve(Object.assign(Object.assign({}, response), { status: (_a = res.statusCode) !== null && _a !== void 0 ? _a : 500 })); | ||
}); | ||
}); | ||
renderReq.on("error", (error) => { | ||
return reject(error); | ||
}); | ||
renderReq.write(JSON.stringify(renderRequest)); | ||
renderReq.end(); | ||
}); | ||
}); | ||
const makeSendEmailRequest = (mailRequest) => __awaiter(void 0, void 0, void 0, function* () { | ||
return yield new Promise((resolve, reject) => { | ||
const sendReq = https_1.default.request({ | ||
hostname: "netlify-integration-emails.netlify.app", | ||
path: "/.netlify/functions/send", | ||
method: "POST", | ||
headers: { | ||
"site-id": process.env.SITE_ID, | ||
"Content-Type": "application/json", | ||
}, | ||
}, (res) => { | ||
let data = ""; | ||
res.on("data", (chunk) => { | ||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands | ||
data += chunk; | ||
}); | ||
res.on("end", () => { | ||
var _a; | ||
const response = JSON.parse(data); | ||
const sendEmailResponse = { | ||
message: response.message, | ||
status: (_a = res.statusCode) !== null && _a !== void 0 ? _a : 500, | ||
}; | ||
resolve(sendEmailResponse); | ||
}); | ||
}); | ||
sendReq.on("error", (error) => { | ||
return reject(error); | ||
}); | ||
sendReq.write(JSON.stringify(mailRequest)); | ||
sendReq.end(); | ||
}); | ||
}); | ||
const handler = (event) => __awaiter(void 0, void 0, void 0, function* () { | ||
var _a, _b, _c, _d; | ||
var _a, _b, _c; | ||
const { default: fetch } = yield Promise.resolve().then(() => __importStar(require("node-fetch"))); | ||
console.log(`Email handler received email request from path ${event.rawUrl}`); | ||
const missingConfig = getMissingConfig(); | ||
const validConfig = isConfigValid(); | ||
const providerApiKey = process.env.NETLIFY_EMAILS_PROVIDER_API_KEY; | ||
@@ -147,86 +90,42 @@ const providerName = process.env.NETLIFY_EMAILS_PROVIDER; | ||
// If missing configuration, render preview HTML and sending missing configuration object to window varialbe | ||
if (missingConfig) { | ||
const missingConfigString = Object.keys(missingConfig) | ||
.map((key) => { | ||
if (missingConfig[key]) { | ||
return key; | ||
} | ||
return ""; | ||
}) | ||
.join(", "); | ||
console.error(`Email handler detected missing configuration: ${missingConfigString}`); | ||
if (event.httpMethod === "POST") { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: `The emails integration is not configured correctly. We have detected the following configuration is missing: ${missingConfigString}`, | ||
}), | ||
}; | ||
} | ||
if (!validConfig) { | ||
return { | ||
statusCode: 200, | ||
body: ` | ||
<html> | ||
<head> | ||
<link rel="stylesheet" href="https://netlify-integration-emails.netlify.app/main.css"> | ||
<script> | ||
missingConfig = ${JSON.stringify(missingConfig)} | ||
siteId = ${JSON.stringify(process.env.SITE_ID)} | ||
templateName = ${JSON.stringify(emailPath)} | ||
</script> | ||
<script defer src='https://netlify-integration-emails.netlify.app/index.js'></script> | ||
</head> | ||
<div id='app'></div> | ||
</html> | ||
`, | ||
<html> | ||
<head> | ||
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script> | ||
<script> | ||
hljs.highlightAll(); | ||
</script> | ||
<link rel="stylesheet" href="https://netlify-integration-emails.netlify.app/main.css"> | ||
<script> | ||
config = ${JSON.stringify({ | ||
NETLIFY_EMAILS_PROVIDER: providerName, | ||
NETLIFY_EMAILS_PROVIDER_API_KEY: providerApiKey, | ||
NETLIFY_EMAILS_MAILGUN_DOMAIN: process.env.NETLIFY_EMAILS_MAILGUN_DOMAIN, | ||
NETLIFY_EMAILS_MAILGUN_HOST_REGION: process.env.NETLIFY_EMAILS_MAILGUN_HOST_REGION, | ||
})} | ||
siteId = ${JSON.stringify(process.env.SITE_ID)} | ||
templateName = ${JSON.stringify(emailPath)} | ||
</script> | ||
<script defer src='https://netlify-integration-emails.netlify.app/index.js'></script> | ||
</head> | ||
<div id='app'></div> | ||
</html> | ||
`, | ||
}; | ||
} | ||
if (event.httpMethod === "GET") { | ||
const showEmailPreview = allowedPreviewEnvironments.includes(process.env.CONTEXT); | ||
if (!showEmailPreview) { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: `Email previews are not allowed in the ${process.env.CONTEXT} environment`, | ||
}), | ||
headers: { | ||
"Content-Type": "text/plain", | ||
}, | ||
}; | ||
} | ||
if (!fs_1.default.existsSync(emailTemplatesDirectory)) { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: `Email templates directory ${emailTemplatesDirectory} does not exist`, | ||
}), | ||
headers: { | ||
"Content-Type": "text/plain", | ||
}, | ||
}; | ||
} | ||
const showEmailPreview = allowedPreviewEnvironments.includes(process.env.CONTEXT); | ||
if (event.httpMethod === "GET" && showEmailPreview) { | ||
let emailTemplate; | ||
if (emailPath !== undefined) { | ||
// Return error if preview path is not a valid email path | ||
if (!fs_1.default.existsSync((0, path_1.join)(emailTemplatesDirectory, emailPath))) { | ||
console.log(`Preview path is not a valid email path - preview path received: ${emailPath}`); | ||
return { | ||
statusCode: 200, | ||
body: ` | ||
<html> | ||
<head> | ||
<link rel="stylesheet" href="https://netlify-integration-emails.netlify.app/main.css"> | ||
<script> | ||
missingTemplate = ${JSON.stringify(true)} | ||
siteId = ${JSON.stringify(process.env.SITE_ID)} | ||
templateName = ${JSON.stringify(emailPath)} | ||
emailDirectory = ${JSON.stringify(emailTemplatesDirectory)} | ||
</script> | ||
<script defer src='https://netlify-integration-emails.netlify.app/index.js'></script> | ||
</head> | ||
<div id='app'></div> | ||
</html> | ||
`, | ||
headers: { | ||
"Content-Type": "text/html", | ||
}, | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: `Preview path is not a valid email path - preview path received: ${emailPath}`, | ||
}), | ||
}; | ||
@@ -236,24 +135,9 @@ } | ||
// If no email template found, return error | ||
if (!emailTemplate) { | ||
if (emailTemplate === undefined) { | ||
console.log(`No email template found for preview path - preview path received: ${emailPath}. Please ensure that an index.mjml or index.html file exists in the email template folder.`); | ||
return { | ||
statusCode: 200, | ||
body: ` | ||
<html> | ||
<head> | ||
<link rel="stylesheet" href="https://netlify-integration-emails.netlify.app/main.css"> | ||
<script> | ||
missingTemplate = ${JSON.stringify(true)} | ||
siteId = ${JSON.stringify(process.env.SITE_ID)} | ||
templateName = ${JSON.stringify(emailPath)} | ||
emailDirectory = ${JSON.stringify(emailTemplatesDirectory)} | ||
</script> | ||
<script defer src='https://netlify-integration-emails.netlify.app/index.js'></script> | ||
</head> | ||
<div id='app'></div> | ||
</html> | ||
`, | ||
headers: { | ||
"Content-Type": "text/html", | ||
}, | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: `No email template found for preview path - preview path received: ${emailPath}`, | ||
}), | ||
}; | ||
@@ -264,2 +148,3 @@ } | ||
fs_1.default.readdirSync(emailTemplatesDirectory).forEach((template) => { | ||
// If index.html or index.mjml exists inside template folder, add to validEmailPaths | ||
if (fs_1.default.existsSync((0, path_1.join)(emailTemplatesDirectory, template, "index.html")) || | ||
@@ -275,2 +160,6 @@ fs_1.default.existsSync((0, path_1.join)(emailTemplatesDirectory, template, "index.mjml"))) { | ||
<head> | ||
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js"></script> | ||
<script> | ||
hljs.highlightAll(); | ||
</script> | ||
<link rel="stylesheet" href="https://netlify-integration-emails.netlify.app/main.css"> | ||
@@ -282,6 +171,8 @@ <script> | ||
siteId = ${JSON.stringify(process.env.SITE_ID)} | ||
siteName = ${JSON.stringify(process.env.SITE_NAME)} | ||
provider = ${JSON.stringify(providerName)} | ||
emailDirectory = ${JSON.stringify(emailTemplatesDirectory)} | ||
secret = ${JSON.stringify(process.env.NETLIFY_EMAILS_SECRET)} | ||
config = ${JSON.stringify({ | ||
NETLIFY_EMAILS_PROVIDER: providerName, | ||
NETLIFY_EMAILS_PROVIDER_API_KEY: providerApiKey, | ||
NETLIFY_EMAILS_MAILGUN_DOMAIN: process.env.NETLIFY_EMAILS_MAILGUN_DOMAIN, | ||
NETLIFY_EMAILS_MAILGUN_HOST_REGION: process.env.NETLIFY_EMAILS_MAILGUN_HOST_REGION, | ||
})} | ||
url = ${JSON.stringify(process.env.URL)} | ||
@@ -300,130 +191,112 @@ templateName = ${JSON.stringify(emailPath)} | ||
} | ||
if (event.httpMethod === "POST") { | ||
if (!process.env.NETLIFY_EMAILS_SECRET) { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: "Secret not set in NETLIFY_EMAILS_SECRET", | ||
}), | ||
}; | ||
} | ||
if (event.headers["netlify-emails-secret"] !== | ||
process.env.NETLIFY_EMAILS_SECRET) { | ||
return { | ||
statusCode: 403, | ||
body: JSON.stringify({ | ||
message: "Secret does not match", | ||
}), | ||
}; | ||
} | ||
// If the email templates directory does not exist, return error | ||
if (!fs_1.default.existsSync(emailTemplatesDirectory)) { | ||
return { | ||
statusCode: 404, | ||
body: JSON.stringify({ | ||
message: `Email templates directory ${emailTemplatesDirectory} does not exist`, | ||
}), | ||
}; | ||
} | ||
if (!event.body) { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: "Request body required", | ||
}), | ||
}; | ||
} | ||
const requestBody = JSON.parse(event.body); | ||
if (!requestBody.from) { | ||
console.log("From address is required"); | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: "From address is required", | ||
}), | ||
}; | ||
} | ||
if (!requestBody.to) { | ||
console.log("To address is required"); | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: "To address is required", | ||
}), | ||
}; | ||
} | ||
if (!emailPath) { | ||
console.error(`Email path is not specified`); | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: "You have not specified the email you wish to send in the URL", | ||
}), | ||
}; | ||
} | ||
const fullEmailPath = `${emailTemplatesDirectory}/${emailPath}`; | ||
const emailPathExists = fs_1.default.existsSync(fullEmailPath); | ||
if (!emailPathExists) { | ||
console.error(`Email path does not exist: ${fullEmailPath}`); | ||
return { | ||
statusCode: 404, | ||
body: JSON.stringify({ | ||
message: `Email path ${fullEmailPath} does not exist`, | ||
}), | ||
}; | ||
} | ||
const email = (0, exports.getEmailFromPath)(fullEmailPath); | ||
if (!email) { | ||
console.error(`No email file found in directory: ${fullEmailPath}`); | ||
return { | ||
statusCode: 404, | ||
body: JSON.stringify({ | ||
message: `No email file found in directory: ${fullEmailPath}`, | ||
}), | ||
}; | ||
} | ||
const renderResponseJson = yield makeRenderTemplateRequest(email, requestBody.parameters); | ||
if ((_c = renderResponseJson.error) !== null && _c !== void 0 ? _c : !renderResponseJson.html) { | ||
console.error(`Error rendering email template: ${JSON.stringify(renderResponseJson)}`); | ||
return { | ||
statusCode: renderResponseJson.status, | ||
body: JSON.stringify({ | ||
message: `Error rendering email template${renderResponseJson.error ? `: ${renderResponseJson.error}` : ""}`, | ||
}), | ||
}; | ||
} | ||
const renderedTemplate = renderResponseJson.html; | ||
const configuration = { | ||
providerName, | ||
apiKey: providerApiKey, | ||
mailgunDomain: process.env.NETLIFY_EMAILS_MAILGUN_DOMAIN, | ||
mailgunHostRegion: process.env.NETLIFY_EMAILS_MAILGUN_HOST_REGION, | ||
if (process.env.NETLIFY_EMAILS_SECRET === undefined || | ||
event.headers["netlify-emails-secret"] !== process.env.NETLIFY_EMAILS_SECRET) { | ||
console.log("No secret provided or secret does not match"); | ||
return { | ||
statusCode: 403, | ||
body: JSON.stringify({ | ||
message: "Request forbidden", | ||
}), | ||
}; | ||
const request = { | ||
from: requestBody.from, | ||
to: requestBody.to, | ||
cc: requestBody.cc, | ||
bcc: requestBody.bcc, | ||
subject: (_d = requestBody.subject) !== null && _d !== void 0 ? _d : "", | ||
html: renderedTemplate, | ||
attachments: requestBody.attachments, | ||
} | ||
if (event.body === null) { | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: "Body required", | ||
}), | ||
}; | ||
const { message, status } = yield makeSendEmailRequest({ | ||
configuration, | ||
request, | ||
}); | ||
if (status !== 200) { | ||
console.error(`Error sending email: ${message}`); | ||
} | ||
} | ||
const requestBody = JSON.parse(event.body); | ||
if (requestBody.from === undefined) { | ||
console.log("From address is required"); | ||
return { | ||
statusCode: status, | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message, | ||
message: "From address is required", | ||
}), | ||
}; | ||
} | ||
if (requestBody.to === undefined) { | ||
console.log("To address is required"); | ||
return { | ||
statusCode: 400, | ||
body: JSON.stringify({ | ||
message: "To address is required", | ||
}), | ||
}; | ||
} | ||
if (emailPath === undefined) { | ||
console.error(`Email path is undefined`); | ||
return { | ||
statusCode: 404, | ||
body: JSON.stringify({ | ||
message: `Email path is undefined`, | ||
}), | ||
}; | ||
} | ||
const fullEmailPath = `${emailTemplatesDirectory}/${emailPath}`; | ||
const directoryExists = fs_1.default.existsSync(fullEmailPath); | ||
if (!directoryExists) { | ||
console.error(`Email directory does not exist: ${fullEmailPath}`); | ||
return { | ||
statusCode: 404, | ||
body: JSON.stringify({ | ||
message: `Email path ${fullEmailPath} does not exist`, | ||
}), | ||
}; | ||
} | ||
const email = (0, exports.getEmailFromPath)(fullEmailPath); | ||
if (email === undefined) { | ||
console.error(`No email file found in directory: ${fullEmailPath}`); | ||
return { | ||
statusCode: 404, | ||
body: JSON.stringify({ | ||
message: `No email file found in directory: ${fullEmailPath}`, | ||
}), | ||
}; | ||
} | ||
const renderResponse = yield fetch("https://netlify-integration-emails.netlify.app/.netlify/functions/render?showParamaterDictionary=true", { | ||
method: "POST", | ||
headers: { | ||
"site-id": process.env.SITE_ID, | ||
}, | ||
body: JSON.stringify({ | ||
template: email.file, | ||
type: email.type, | ||
parameters: requestBody.parameters, | ||
showParamatersDictionary: false, | ||
}), | ||
}); | ||
const renderResponseJson = (yield renderResponse.json()); | ||
const renderedTemplate = renderResponseJson.html; | ||
const response = yield fetch("https://test-netlify-integration-emails.netlify.app/.netlify/functions/send", { | ||
method: "POST", | ||
headers: { | ||
"site-id": process.env.SITE_ID, | ||
"content-type": "application/json", | ||
}, | ||
body: JSON.stringify({ | ||
configuration: { | ||
providerName, | ||
apiKey: providerApiKey, | ||
mailgunDomain: process.env.NETLIFY_EMAILS_MAILGUN_DOMAIN, | ||
mailgunHostRegion: process.env.NETLIFY_EMAILS_MAILGUN_HOST_REGION, | ||
}, | ||
request: { | ||
from: requestBody.from, | ||
to: requestBody.to, | ||
cc: requestBody.cc, | ||
bcc: requestBody.bcc, | ||
subject: (_c = requestBody.subject) !== null && _c !== void 0 ? _c : "", | ||
html: renderedTemplate, | ||
attachments: requestBody.attachments, | ||
}, | ||
}), | ||
}); | ||
const responseText = yield response.text(); | ||
return { | ||
statusCode: 405, | ||
statusCode: response.status, | ||
body: JSON.stringify({ | ||
message: "Method not allowed", | ||
message: responseText, | ||
}), | ||
@@ -430,0 +303,0 @@ }; |
@@ -6,2 +6,3 @@ export declare const onPreBuild: ({ netlifyConfig, }: { | ||
included_files: string[]; | ||
external_node_modules: string[]; | ||
}; | ||
@@ -8,0 +9,0 @@ }; |
@@ -7,2 +7,3 @@ "use strict"; | ||
exports.onPreBuild = void 0; | ||
// import { execSync } from "child_process"; | ||
const fs_1 = __importDefault(require("fs")); | ||
@@ -17,4 +18,15 @@ const path_1 = require("path"); | ||
else { | ||
netlifyConfig.functions.emails = Object.assign(Object.assign({}, netlifyConfig.functions.emails), { included_files: [`${emailsDirectory}/**`] }); | ||
netlifyConfig.functions.emails = Object.assign(Object.assign({}, netlifyConfig.functions.emails), { included_files: [`${emailsDirectory}/**`], external_node_modules: ["node-fetch@2"] }); | ||
} | ||
// const functionDependencies = ["node-fetch@2"]; | ||
// // Detect whether project is using NPM, Yarn or Pnpm | ||
// let packageManager = "npm"; | ||
// if (fs.existsSync("yarn.lock")) { | ||
// packageManager = "yarn"; | ||
// } else if (fs.existsSync("pnpm-lock.yaml")) { | ||
// packageManager = "pnpm"; | ||
// } | ||
// console.log("Installing email function dependencies"); | ||
// execSync(`${packageManager} install ${functionDependencies.join(" ")} -D`); | ||
// console.log("Installed email function dependencies"); | ||
const emailFunctionDirectory = (0, path_1.join)(".netlify", "functions-internal", "emails"); | ||
@@ -21,0 +33,0 @@ fs_1.default.mkdirSync(emailFunctionDirectory, { |
{ | ||
"name": "@netlify/plugin-emails", | ||
"version": "0.4.6-preview", | ||
"version": "1.0.0", | ||
"description": "A build plugin that creates an email handler and processes requests to send emails", | ||
@@ -5,0 +5,0 @@ "main": "./lib/index.js", |
# Netlify Emails Plugin | ||
🚧 Note: This plugin is pre-release software. Until version 1.0.0 is released, its API could change at any time. | ||
The Netlify emails build plugin is responsible for creating a serverless function to handle email requests, using the email request to populate provided email templates and sending them using the specified email API provider. | ||
@@ -9,3 +7,3 @@ | ||
Full documentation for the Netlify Email Integration can be found [here](https://docs.netlify.com/netlify-labs/experimental-features/email-integration). | ||
Full documentation for the Netlify Email Integration can be found [here](https://docs.netlify.com/integrations/email-integration). | ||
@@ -36,3 +34,3 @@ ## Supported email providers | ||
Each email template should be stored under a folder name that represents the route of your template and the email file should be named `index.html`. E.g. `./emails/welcome/index.html`. | ||
We support both HTML and responsive [MJML](https://mjml.io/) templates. Each email template should be stored under a folder name that represents the route of your template and the email file should be named either `index.html` or `index.mjml`. E.g. `./emails/welcome/index.html`. | ||
@@ -54,3 +52,3 @@ If there are variables that need replacing in your email template when the email is triggered, please use the [handlebars.js](https://handlebarsjs.com/) syntax and pass the arguments in the request as shown in Step 5 below. | ||
Visit `http://localhost:{PORT}/.netlify/functions/emails/_preview` to preview your email templates. | ||
Visit `http://localhost:{PORT}/.netlify/functions/emails` to preview your email templates. | ||
@@ -61,5 +59,24 @@ Please note, this preview endpoint is not made available in production and is only made available locally. | ||
Dependent on where you would like to trigger an email being sent (on a subscribe or data request button click, when an event is triggered, etc.), add this snippet to your code that is reacting to that event. | ||
Dependent on where you would like to trigger an email being sent (on a subscribe or data request button click, when an event is triggered, etc.), add one of the following snippets to your code that is reacting to that event. | ||
**@netlify/emails:** | ||
``` | ||
await sendEmail({ | ||
from: "no-reply@yourdomain.com", | ||
to: "alexanderhamilton@test.com", | ||
cc: "cc@test.com", | ||
bcc: "bcc@test.com", | ||
subject: "Welcome", | ||
template: "welcome", | ||
parameters: { | ||
products: ["product1", "product2", "product3"], | ||
name: "Alexander", | ||
}, | ||
}); | ||
``` | ||
**node-fetch:** | ||
``` | ||
import fetch from 'node-fetch' | ||
@@ -66,0 +83,0 @@ |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
1
103
26
65208
21
1617
2