Создайте целевую страницу, которая позволит компании собирать потенциальных клиентов в форме электронных писем пользователей и отправлять автоматические электронные письма через заранее определенные интервалы времени.
Автор: Алекс Годвин
Автоматизация электронной почты — важнейший компонент современного маркетинга. Это позволяет компаниям и предприятиям обращаться к большому количеству потенциальных клиентов и информировать существующих клиентов о новых продуктах и политике компании.
Использование задач Strapi cron для автоматизации электронной почты — мощная концепция. В этом руководстве мы создадим целевую страницу, которая позволит компании собирать потенциальных клиентов в виде электронных писем пользователей и отправлять автоматические электронные письма через заранее определенные интервалы.
Предпосылки
Завершенная версия вашего приложения должна выглядеть так, как показано на рисунке ниже:
Введение в Страпи
В документации Strapi говорится, что Strapi — это гибкая система Headless CMS с открытым исходным кодом, которая дает разработчикам свободу выбора своих любимых инструментов и фреймворков, а также позволяет редакторам легко управлять своим контентом и распространять его.
Strapi позволяет крупнейшим мировым компаниям ускорить доставку контента, одновременно создавая прекрасные цифровые возможности, делая панель администратора и API расширяемыми с помощью системы плагинов.
Создание строительных лесов для проекта Strapi
Чтобы установить Strapi, перейдите к документации Strapi на сайте Strapi. Мы будем использовать базу данных SQLite для этого проекта. Чтобы установить Strapi, выполните следующие команды:
yarn create strapi-app my-project # using yarn
npx create-strapi-app@latest my-project # using npx
Замените my-project
именем, которое вы хотите назвать своим каталогом приложений. Ваш менеджер пакетов создаст каталог с указанным именем и установит Strapi.
Если вы правильно следовали инструкциям, на вашем компьютере должен быть установлен Strapi. Выполните следующие команды, чтобы запустить сервер разработки Strapi:
yarn develop # using yarn
npm run develop # using npm
Сервер разработки запускает приложение на https://localhost:1337/admin.
Создание типа коллекции списка рассылки
Давайте создадим наш тип коллекции Mailing-list
, который будет содержать адреса электронной почты подписчиков:
- Нажмите на
Content-Type Builder
подPlugins
в боковом меню. - Под
collection types
нажмитеcreate new collection type
. - Создайте новый
collection-type
с именемMailing-list
. - Создайте следующие поля в разделе
*product content-type*
:
email
asEmail
Создание типа коллекции шаблонов электронной почты
Затем мы создаем наш тип коллекции Email-template
, который будет моделью для отправляемых нами электронных писем:
- Нажмите на
Content-Type Builder
подPlugins
в боковом меню. - Под
collection types
нажмитеcreate new collection type
- Создайте новый
collection-type
с именемEmail-template
. - Создайте следующие поля под
product content-type
:
Subject
asText
Content
asRichText
Это позволит нам создавать электронные письма, которые мы отправляем нашим пользователям.
Введение в рабочие места CRON
Cron Jobs используются для различных целей. Задания Cron используются для планирования выполнения задач на сервере. Чаще всего они используются для автоматизации управления или обслуживания системы. Тем не менее, они также применимы при создании веб-приложений. Веб-приложение может потребоваться для выполнения определенных операций на регулярной основе в различных обстоятельствах.
Зачем использовать задания Cron?
- Если у вас есть членский сайт с датами истечения срока действия, вы можете использовать задачи cron для деактивации или удаления учетных записей, срок действия которых истек на регулярной основе.
- У вас есть возможность отправлять ежедневные информационные бюллетени по электронной почте.
- Планирование мероприятий, проводимых на регулярной основе.
Структура заданий Cron
'* * * * * *'
* * * * * * ┬ ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ | │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) │ │ │ │ └───── month (1 - 12) │ │ │ └────────── day of month (1 - 31) │ │ └─────────────── hour (0 - 23) │ └──────────────────── minute (0 - 59) └───────────────────────── second (0 - 59, OPTIONAL)
Настройка заданий Cron в Strapi
Выполните следующие действия, чтобы настроить задание cron в приложении Strapi:
- Откройте файл
config/server.js
, затем добавьте следующие строки кода в конфигурацию сервера.
cron: {
enabled: true,
tasks: cronTasks,
}
- Создайте файл
cron-task.js
в папкеconfig
и добавьте следующее
module.exports = {
'01 10 16 * * *': async ({ strapi }) => {
console.log('cron running')
}
Создать задание cron в Strapi очень просто.
Настройка провайдера электронной почты в Strapi
Мы настроим @strapi/provider-email-nodemailer
.
- Чтобы установить пакет, выполните:
npm i @strapi/provider-email-nodemailer
- В
config/plugins.js
добавьте следующее:
module.exports = ({ env }) => ({
email: {
config: {
provider: 'nodemailer',
providerOptions: {
host: env('SMTP_HOST'),
port: env('SMTP_PORT'),
auth: {
user: env('SMTP_USERNAME'),
pass: env('SMTP_PASSWORD'),
},
pool: true,
logger: true,
debug: true,
maxConnections: 10000
},
settings: {
defaultFrom: env('DEFAULT_EMAIL'),
defaultReplyTo: env('DEFAULT_EMAIL'),
},
},
},
});
- Создайте файл
.env
и добавьте в него свои учетные данные:
SMTP_HOST=YOUR_SMTP_HOST
SMTP_PORT=465
SMTP_USERNAME=YOUR_SMTP_USERNAME
SMTP_PASSWORD=YOUR_SMTP_PASSWORD
DEFAULT_EMAIL=YOUR_EMAIL_ADDRESS
Вы можете использовать любого поставщика почтовых услуг по вашему выбору.
Теперь, когда у нас есть служба электронной почты, мы можем обновить наш файл cron-job.js
, чтобы правильно отправлять электронные письма.
Откройте файл cron-task.js
и отредактируйте его содержимое с помощью следующих строк кода:
const marked = require('marked')
module.exports = {
'01 13 15 * * *': async ({ strapi }) => {
console.log('cron running')
try {
let emails = await strapi.service('api::email-template.email-template').find()
emails = emails.results.reverse()
const subscribers = await strapi.service('api::mailing-list.mailing-list').find()
const content = marked.parse(emails[0].Content)
await Promise.all(subscribers.results.map(async (el, i) => {
return await strapi
.plugin('email')
.service('email')
.send({
to: el.email,
subject: 'Test mail',
html: content,
});
}))
} catch (error) {
console.log(error)
}
},
};
Вы можете настроить задание CRON на любое время. Кроме того, наша логика гласит, что мы получим самое последнее электронное письмо от нашего email-template
и отправим его всем пользователям в нашем mailing-list
.
Создание приложения, которое собирает электронные письма пользователей и добавляет их в наш список рассылки
Очевидно, нам нужно средство для сбора фактических электронных писем для нашего списка рассылки. Мы создадим внешний интерфейс нашего приложения, используя Vue 3. Vue
— это JavaScript-фреймворк для создания пользовательских интерфейсов.
Выполните следующую команду, чтобы установить vue
:
mkdir client
npm init vue@latest
Дайте соответствующие ответы на запросы, затем выполните следующие команды:
cd <your-project-name>
npm install
npm run dev
Ваше приложение vue
должно работать на указанном порту. Откройте файл app.vue
и обновите его следующим кодом:
<script setup>
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from '@/components/HelloWorld.vue'
</script>
<template>
<header>
<div class="wrapper">
<HelloWorld msg="Welcome to UoRos" />
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
</nav>
</div>
</header>
<RouterView />
</template>
<style>
@import '@/assets/base.css';
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
font-weight: normal;
}
header {
line-height: 1.5;
max-height: 100vh;
}
.logo {
display: block;
margin: 0 auto 2rem;
}
a,
.green {
text-decoration: none;
color: hsla(160, 100%, 37%, 1);
transition: 0.4s;
}
@media (hover: hover) {
a:hover {
background-color: hsla(160, 100%, 37%, 0.2);
}
}
nav {
width: 100%;
font-size: 12px;
text-align: center;
margin-top: 2rem;
}
nav a.router-link-exact-active {
color: var(--color-text);
}
nav a.router-link-exact-active:hover {
background-color: transparent;
}
nav a {
display: inline-block;
padding: 0 1rem;
border-left: 1px solid var(--color-border);
}
nav a:first-of-type {
border: 0;
}
@media (min-width: 1024px) {
body {
display: flex;
place-items: center;
}
#app {
display: grid;
grid-template-columns: 1fr 1fr;
padding: 0 2rem;
}
header {
display: flex;
place-items: center;
padding-right: calc(var(--section-gap) / 2);
}
header .wrapper {
display: flex;
place-items: flex-start;
flex-wrap: wrap;
}
.logo {
margin: 0 2rem 0 0;
}
nav {
text-align: left;
margin-left: -1rem;
font-size: 1rem;
padding: 1rem 0;
margin-top: 1rem;
}
}
</style>
Откройте компонент HelloWorld.vue
и обновите его следующим кодом:
<script setup>
defineProps({
msg: {
type: String,
required: true
}
})
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
UoRos is a Futuristic company, invested in making sustainabile energy.
</h3>
<h3>
<strong class="bold">
Solar + Renewable energy
</strong>
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.bold {
font-weight: 900;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>
В компоненте TheWelcome.vue
поместите следующий код:
<script setup>
import WelcomeItem from './WelcomeItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import CommunityIcon from './icons/IconCommunity.vue'
import SupportIcon from './icons/IconSupport.vue'
</script>
<template>
<WelcomeItem>
<template #icon>
<DocumentationIcon />
</template>
<template #heading>Vision</template>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Voluptatibus corrupti eveniet asperiores assumenda, sit quia eligendi porro exercitationem! Vitae ab veniam dolorum voluptates! Iste rerum molestiae nobis tenetur unde odit.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<ToolingIcon />
</template>
<template #heading>Purpose</template>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Alias optio, facere velit officiis dolore doloremque ipsa minima, explicabo, fugiat placeat debitis repellat. Assumenda accusantium enim, aspernatur nemo illo ducimus quia.
<br />
</WelcomeItem>
<WelcomeItem>
<template #icon>
<EcosystemIcon />
</template>
<template #heading>Ecosystem</template>
Lorem, ipsum dolor sit amet consectetur adipisicing elit. Architecto beatae officia culpa animi quas labore! Ducimus tempora, voluptatibus illo laudantium laborum repudiandae tempore labore fugit at excepturi dolore placeat minus?
</WelcomeItem>
</template>
Обновите компонент About.vue
следующим кодом:
<template>
<div class="about">
<div>
<h1 class="heading">
About UoRos
</h1>
<p class="desc_text">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Esse maiores velit molestias assumenda numquam eligendi. Perferendis pariatur, eligendi at nostrum odio ducimus quod consequatur dignissimos culpa magni commodi, quo esse!
</p>
<h1 class="heading">
What we do
</h1>
<p class="desc_text">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Esse maiores velit molestias assumenda numquam eligendi. Perferendis pariatur, eligendi at nostrum odio ducimus quod consequatur dignissimos culpa magni commodi, quo esse!
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Placeat voluptatibus officia atque fuga nesciunt rem iste ab saepe ducimus, praesentium soluta quis temporibus, tempora voluptas facere quos reprehenderit beatae in!
</p>
<h1 class="heading">
Join our mailing list
</h1>
<p class="desc_text">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Delectus eum assumenda dolor laudantium sed temporibus nulla sunt dicta voluptatibus asperiores harum officiis, at, quibusdam beatae corrupti. Suscipit placeat modi corrupti!
</p>
<div>
<form action="" @submit="signUpToMail">
<p>{{ error }}</p>
<input type="email" class="email_input" name="email" placeholder="Email address" id="" v-model="email">
<input type="submit" class="email_submit" value="Sign up">
</form>
</div>
</div>
</div>
</template>
<style>
@media (min-width: 1024px) {
.about {
min-height: 100vh;
display: flex;
align-items: center;
}
.heading {
/* margin: 10px 0; */
font-weight: 700;
}
.desc_text {
margin: 0 0 15px 0;
}
.email_input {
padding: 12px 10px;
font-size: 16px;
border: none;
background: rgb(232, 240, 254)
}
.email_submit {
background-color: hsla(160, 100%, 37%, 1); /* Green */
border: none;
color: white;
padding: 12px 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 0 5px;
}
}
</style>
<script>
import axios from 'axios'
export default {
data() {
return {
email: '',
error: ''
}
},
methods: {
async signUpToMail(e) {
e.preventDefault()
if(!this.email) return this.error = `Enter an email address`
const data = {
data: {email: this.email}
}
console.log('Email', this.email)
try {
await axios(`https://localhost:1337/api/mailing-lists`, {
method: 'POST',
data
})
} catch (error) {
console.log(error)
}
this.email = ''
this.error = ''
}
}
}
</script>
Этот компонент отвечает за вызов API к нашему серверу Strapi.
В старой документации Strapi сказано следующее:
Please note that Strapi's built in CRON feature will not work if you plan to use pm2 or node based clustering. You will need to execute these CRON tasks outside of Strapi.
Проблема
Например, вы можете развернуть приложение Strapi в нескольких контейнерах/кластерах/экземплярах, чтобы повысить производительность (горизонтальное масштабирование). Это может быть, например, несколько кластеров pm2 или экземпляров Google App Engine, в зависимости от хостинга.
Если вы развернули приложение Strapi в нескольких экземплярах, то каждый из них будет запускать задание cron, а затем, например, у вас может быть дублированная отправка электронных писем, поскольку оно было запущено и выполнено более чем в одном экземпляре.
Решением для этого может быть использование сторонней службы, которая обрабатывает планирование, например, с помощью cron, а затем использует пользовательскую конечную точку для запуска (в одном экземпляре) пользовательского кода один раз.
Возможное решение
Вы можете создать собственный маршрут/контроллер, который будет выполнять ту же логику, что и crontask (возможно, реализовать токены API для его защиты). Затем вы вызовете эту конечную точку из любой другой системы.
Это может быть встроенная система заданий CRON в Linux с простым запросом на завивание или использование более сложной собственной системы cron. Вы даже можете использовать такие вещи, как Zapier или IFTTT, неважно, что это такое, пока он может сделать запрос GET, POST или PUT, который вы хотите (обычно GET).
Таким образом, конечная точка «crontask» будет выполняться только на одном узле кластера.
Заключение
Наконец, у нас есть полноценное приложение, которое позволит нам собирать электронные письма и регулярно отправлять им новую информацию о нашей компании в назначенное время.