Моя цель — отправить электронное письмо со страницы контактов статического веб-приложения Azure с помощью функции Azure. Мне удалось заставить это работать, как описано ниже, поэтому мой вопрос: «Как это можно сделать лучше в функциях Azure?»
Очевидно, нельзя использовать службы связи Azure из функции Azure для отправки электронной почты. Мне удалось заставить это работать в эмуляции локального статического веб-приложения (SWA), но при запуске из Azure это происходит автоматически.
Я забил и создал учетную запись SendGrid. Он предлагает 100 бесплатных сообщений в день бесплатно, так что это хорошая альтернатива.
Все справочные материалы, которые я могу найти, ссылаются на интеграцию с использованием модели программирования Azure node.js v3, которая включает файлы конфигурации function.json. По этому поводу даже есть проблема с репозиторием Microsoft Docs на GitHub: https://github.com/MicrosoftDocs/azure-docs/issues/119439
Поскольку модель программирования Azure node.js v4 (далее просто «v4») является моделью по умолчанию и стандартом, я решил, что не хочу использовать v3.
Пример кода SendGrid работает практически сразу после установки, но когда вы оборачиваете его в асинхронную функцию для версии 4, вам нужно дождаться операции «.send». Если вы этого не сделаете, функция фактически завершит работу, и вы получите значение ответа «неожиданное состояние» (используя мой код; сообщение по-прежнему отправляется в локальной среде, но на это нельзя рассчитывать). Здесь проявляется моя слабость к JS async, потому что я думал, что then/catch — это другой способ работы с промисами.
Вот мой рабочий код:
const { app } = require("@azure/functions");
const mta = require("@sendgrid/mail");
app.http("sendGrid", {
methods: ["GET", "POST"],
authLevel: "anonymous",
handler: async (request, context) => {
const key = process.env.SENDGRID_API_KEY;
var response = 'unexpected state'
var code = 200;
// Authenticate
mta.setApiKey(key);
// Timestamp for this invocation
const timestamp = new Date(Date.now());
// Build a message
const content = {
to: "user@domain", /* <== replace with your target email address */
from: "user@domain", /* <== replace with authenticated sender address */
subject: `SendGrid message ${timestamp}`,
text: `SendGrid message body text ${timestamp}`,
html: `SendGrid message body html <strong>${timestamp}</strong>`
};
await mta.send(content)
.then(() => {
response = `message ${timestamp} sent`;
code = 200;
})
.catch((thrown) => {
response = `message not sent ${thrown}`;
code = 500;
});
context.log(response);
return { status: code, body: response };
}
});
🤔 А знаете ли вы, что...
Node.js поддерживает работу с файлами и директориями на сервере.
Чтобы отправлять электронную почту из статического веб-приложения Azure с помощью функции Azure версии 4, вам необходимо добавить приложение внешнего интерфейса для вызова конечной точки API. Я использовал файл _src/index.html_
, чтобы получить текст из функции API и отобразить его на экране, который действует как никакой фреймворк.
Я использовал этот MSDOC, чтобы добавить API к статическим веб-приложениям Azure с функциями Azure.
Ниже приведен простой HTML-код, который используется для запуска/отображения результатов. Функция Azure для отправки электронного письма с помощью SendGrid.
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<meta name = "viewport" content = "width=device-width, initial-scale=1.0">
<title>API Response Display</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.response {
margin-top: 20px;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
}
.success {
background-color: #e6ffed;
border-color: #a3d9a5;
}
.failure {
background-color: #ffe6e6;
border-color: #d9a5a5;
}
</style>
</head>
<body>
<h1>API Response Display</h1>
<button id = "fetchButton">Fetch API Response</button>
<div id = "responseContainer" class = "response"></div>
<script>
document.getElementById('fetchButton').addEventListener('click', async () => {
const responseContainer = document.getElementById('responseContainer');
responseContainer.innerHTML = 'Fetching...';
try {
const response = await fetch('/api/httpTrigger');
const data = await response.json();
if (response.ok) {
responseContainer.innerHTML = `
<div class = "success">
<h2>Success</h2>
<pre>${JSON.stringify(data, null, 2)}</pre>
</div>
`;
} else {
responseContainer.innerHTML = `
<div class = "failure">
<h2>Failure</h2>
<pre>${JSON.stringify(data, null, 2)}</pre>
</div>
`;
}
} catch (error) {
responseContainer.innerHTML = `
<div class = "failure">
<h2>Error</h2>
<pre>${error}</pre>
</div>
`;
}
});
</script>
</body>
</html>
Структура папки Git:
yml
в соответствии со структурой вашей папки. app_location to "./src"
api_location to "./api1"
output_location to "."
Обратитесь к этому SO для файла конфигурации рабочего процесса yml в Static Web App. Статус развертывания
Конечная точка приложения функции должна иметь префикс /api
, поскольку Static Web Apps сопоставляет запросы, отправленные к /api
.
Существующее приложение «Функции Azure» предоставляет конечную точку через следующий пример URL-адреса.
https:/nameofazuresataticwebapp.azurewebsites.net/api/functionname
, как показано на изображении ниже.
Приложение «Функции Azure» со статическим выводом Azure:
Статический вывод Azure: