Настройка отправки писем через серверное приложение SmartPlayer

Материал из SmartPlayer

Описание

Серверное приложение SmartPlayer имеет ряд функциональностей, где происходит оповещение конечного пользователя через почтовый сервер, например:

  • Изменение статуса устройства (онлайн, оффлайн и т.п.)
  • Оповещение о проблемных товарных позициях по товару
  • Оповещение о неуспешном снятие бэкапа сервера и другие.

Ключевые моменты

Серверное приложение SmartPlayer не имеет встроенного почтового сервера, так как это отдельная большая разработка на которой специализируются отдельный ИТ компании. Серверное приложении имеет только клиента, который может отправлять сообщения используя почтовый сервер.
Почтовые сервера могут быть установлены как в локальной сети, так и в публичной (называем их облачными).
К локальным из самых популярных можно отнести Microsoft Exchange. Локальным его делает то, что он установлен внутри закрытого контура локальной сети. В больших корпорациях в 99% так и есть.
К облачным почтовым серверам можно отнести SendPulse именно его использует SmartPlayer в облачных решениях для отправки писем. Настройки для облачного почтового сервера, можно получить у @Андрей Никонов . А для локального почтового сервера, настройки необходимо получать у местного системного администратора заказчика, чтобы их получить нужно задать правильные вопросы которые описаны в следующем разделе.

Основные вопросы и ответы для местного системного администратора

Есть ли локальный почтовый сервер у заказчика в внутренней сети ?

  • Если на этот вопрос ответ нет, то остальные не имеют смысла

Какой использовать host для подключения к почтовому серверу ?

  • Ответ на этот вопрос будет означать значение параметра: host в конфигурации

Какой использовать порт для подключения к почтовому серверу ?

  • Ответ на этот вопрос будет означать значение параметра: port в конфигурации

Требуется ли авторизация на почтовом сервере для отправки писем ?

  • Ответ на этот вопрос будет означать значение параметра-объекта : auth в конфигурации

От какого e-mail отправлять письма ?

  • По умолчанию используется почта noreply@smartplayer.org, но почтовый сервер может фильтровать такие письма и требовать чтобы отправка писем выполнялась от реально существующего аккаунта на почтовом сервере. Ответ на этот вопрос будет означать значение параметра : defaultSenderEmail в конфигурации

Принимает ли сервер незашифрованные запросы ?

  • Ответ на этот вопрос будет означать значение параметров безопасности таки как : secure, ignoreTLS, rejectUnauthorized в конфигурации

После того как получены ответы на вопросы, можно приступать к настройки конфигурации серверного приложения для отправки писем.

Общая информация по настройке клиента серверного приложения, который используется для отправки писем

С версии сервера 2.85.0 добавлена отправка email уведомлений ошибок о товарах. Отправителем письма указывается modules.priceList.methods.checkAllPriceList.NO_REPLY_EMAIL в файле local.json - по умолчанию noreply@smartplayer.org

О том как заполнять файл Local.js и для чего он нужен также описано в отдельной инструкции

До версии сервера 2.87.1 существовал один режим отправки email уведомлений ошибок о товарах: email сообщение отправляется на SMTP сервер, хост которого получается по MX записи доменного имени получателя сообщения. Это приводило к проблемам отправки писем в локальной сети, т.к. зачастую по MX записям письма отправить не удавалось + используемый модуль не поддерживает
С версии сервера 2.87.1 существует два режима отправки email уведомлений, которые задаются в файле local.json:

  • direct - значение по-умолчанию - email сообщение отправляется на SMTP сервер, хост которого получается по MX записи доменного имени получателя сообщения.
  • through SMTP server - email сообщение отправляется на SMTP сервер, параметры подключения к которому указываются в настройке smtpServerConnectionParams.

Клиент имеет дополнительные опции, которые описаны в документации модуля https://nodemailer.com/smtp/ может быть полезно, при уникальной настройки, но 90% случаев будет достаточно примеров, которые будут описаны ниже.

Настройка отправки писем с серверного приложения для всех функциональностей где используется отправка писем

Таблица параметров
Название параметра Описание параметра
host Адрес почтового сервера, который получен от администратора локального/облачного почтового сервера.
port Порт почтового сервера, который получен от администратора локального/облачного почтового сервера.
auth

Объект который содержит данные для авторизации на почтовом сервере. Его стоит заполнять если почтовый сервер требует авторизации.

"rejectUnauthorized": false Описание из официальной документации:

rejectUnauthorized <boolean> If not false a server automatically reject clients with invalid certificates.

secure Описание из официальной документации:

secure – if true the connection will use TLS when connecting to server. If false (the default) then TLS is used if server supports the STARTTLS extension. In most cases set this value to true if you are connecting to port 465. For port 587 or 25 keep it false

ignoreTLS Описание из официальной документации:

ignoreTLS – if this is true and secure is false then TLS is not used even if the server supports STARTTLS extension

defaultSenderEmail От кого (какого e-mail) отправлять письма

Примеры

Пример с авторизацией и типом отправки “through SMTP server“ local.js:

module.exports = {
    services: {        
        sendMessage: {
            TRANSPORTS: [
                {
                    transportId: 'localSMTPEmailTransport',
                    type: 'email',
                    params: {
                        mode: 'through SMTP server',
                        smtpServerConnectionParams: {
                            "host": "mail.example.com",
                            "port": 465,
                            "auth": {
                                "user": "username",
                                "pass": "password"
                            },
                            "secure": false,
                            "tls": {
                                "rejectUnauthorized": false
                            },
                            "ignoreTLS": true
                        },
                        retriesCount: 2,
                        defaultSenderEmail: 'noreply@smartplayer.org',
                        concurrency: 10,
                        toStoreFields: null,
                        toExcludeFields: ['attachments']
                    }
                }
            ],
            DEFAULT_EMAIL_TRANSPORT_ID: 'localSMTPEmailTransport'
        }
    }
}

Пример без авторизации и типом отправки “through SMTP server“ local.js:

module.exports = {
    services: {        
        sendMessage: {
            TRANSPORTS: [
                {
                    transportId: 'localSMTPEmailTransport',
                    type: 'email',
                    params: {
                        mode: 'through SMTP server',
                        smtpServerConnectionParams: {
                            "host": "mail.example.com",
                            "port": 465,                            
                            "secure": false,
                            "tls": {
                                "rejectUnauthorized": false
                            },
                            "ignoreTLS": true
                        },
                        retriesCount: 2,
                        defaultSenderEmail: 'noreply@smartplayer.org',
                        concurrency: 10,
                        toStoreFields: null,
                        toExcludeFields: ['attachments']
                    }
                }
            ],
            DEFAULT_EMAIL_TRANSPORT_ID: 'localSMTPEmailTransport'
        }
    }
}

В некоторых случаях может потребоваться прямая отправка “direct“, тогда конфиг будет выглядеть так без авторизации.

module.exports = {
    services: {        
        sendMessage: {
            TRANSPORTS: [
                {
                    transportId: 'directEmailTransport',
                    type: 'email',
                    params: {
                        mode: 'direct',
                        retriesCount: 2,
                        defaultSenderEmail: 'noreply@smartplayer.org',
                        concurrency: 10,
                        toStoreFields: null,
                        toExcludeFields: ['attachments']
                    }
                }
            ],
            DEFAULT_EMAIL_TRANSPORT_ID: 'directEmailTransport'
        }
    }
}
Пример отправки от имени личного аккаунта на gmail

Для отправки писем от имени своего аккаунта на gmail (это может потребоваться для тестирования), можно в настройках серверного приложения services.sendMessage.TRANSPORTS указать:

module.exports = {
    services: {        
        sendMessage: {
            TRANSPORTS: [
                {
                    transportId: 'gmailSMTPEmailTransport',
                    type: 'email',
                    params: {
                        mode: 'through SMTP server',
                        smtpServerConnectionParams: {
                            "host": "smtp.gmail.com",
                            "port": 465,
                            "auth": {
                                "user": "f.nasybulin@smartplayer.org",
                                "pass": "password"
                            },
                            "secure": false,
                            "tls": {
                                "rejectUnauthorized": false
                            },
                            "ignoreTLS": true
                        },
                        retriesCount: 2,
                        defaultSenderEmail: 'noreply@smartplayer.org',
                        concurrency: 10,
                        toStoreFields: null,
                        toExcludeFields: ['attachments']
                    }
                }
            ],
            DEFAULT_EMAIL_TRANSPORT_ID: 'gmailSMTPEmailTransport'
        }
    }
}

И включить отправку писем со всех сторонних приложений в настройках своего аккаунта Google

Настройка отправки писем с серверного приложения для валидации товарных позиций (в основном использовалось для проекта "Окей", но не ограничивается им)

Есть возможность выбрать через какой транспорт отправлять письма для определенных модулей, а не использовать DEFAULT_EMAIL_TRANSPORT_ID как в предыдущих примера. Тут показан пример для настроек параметров под модули, которые отвечают за справочник товары.

Пример local.js:

Для этого нужно указать несколько транспортов (описать параметры подключения) и указать какой именно использовать в данном модуле. Например письма при возникновении ошибок в сведения о товарах отправлять через gmailSMTPEmailTransport, а все остальные через directEmailTransport:

{
  "modules": {
    "priceList":{
      "methods": {
        "checkAllPriceLists": {
          "EMAIL_TRANSPORT_ID": "gmailSMTPEmailTransport"
        }
      }
    }
  },
  services: {        
        sendMessage: {
            TRANSPORTS: [
                {
                    transportId: 'gmailSMTPEmailTransport',
                    type: 'email',
                    params: {
                        mode: 'through SMTP server',
                        smtpServerConnectionParams: {
                            "host": "smtp.gmail.com",
                            "port": 465,
                            "auth": {
                                "user": "f.nasybulin@smartplayer.org",
                                "pass": "password"
                            },
                            "secure": false,
                            "tls": {
                                "rejectUnauthorized": false
                            },
                            "ignoreTLS": true
                        },
                        retriesCount: 2,
                        defaultSenderEmail: 'noreply@smartplayer.org',
                        concurrency: 10,
                        toStoreFields: null,
                        toExcludeFields: ['attachments']
                    }
                },
                {
                    transportId: 'directEmailTransport',
                    type: 'email',
                    params: {
                        mode: 'direct',
                        retriesCount: 2,
                        defaultSenderEmail: 'noreply@smartplayer.org',
                        concurrency: 10,
                        toStoreFields: null,
                        toExcludeFields: ['attachments']
                    }
                }
            ],
            DEFAULT_EMAIL_TRANSPORT_ID: 'directEmailTransport'
        }
    }
}

Установка конфигурации серверного приложения на целевой сервер

  1. К этому моменту у нас есть файл local.js который содержит в себе настройки для клиента отправки писем со стороны серверного приложения
  2. Загрузите этот файл любым удобным способом на сервер:
  3. Скопируйте этот файл в папку серверного приложения с именем config, по умолчанию это для docker сборки будет путь “/home/smartplayer/smartplayer/backend/app/config“. defaults.js конфиг не удаляйте, требуемые параметры будут перезаписаны из local.js
  4. Перезапустить серверное приложение

docker exec -it smartplayer_backend_1 sh -c "pm2 restart all"

Проверяем как работают наши новые настройки серверного приложения

Отправка тестового письма средствами серверного приложения SmartPlayer

Внимание! Функция доступна с версии серверного приложения v2.131.0 и выше

Для отправки тестового письма добавлена команда node ./cli.js email send
После ввода команды нужно будет ввести e-mail на который отправить сообщение и будут предложены на выбор доступные transport-ы для отправки письма.
Также для проверки отправки письма на кастомном конфиге есть команда node ./cli.js test send-mail с опциями --from - от кого будет отправлено письмо --to - кому будет отправлено письмо --nodemailerOptions - NodeMailer конфиг --sendmailOptions - конфиг smtp сервера
Для получения информации об отправленных письмах была добавлена команда: node ./cli.js email get
По дефолту команда выведет 10 последних записей без текста сообщений и без текста ошибок.
Пример: Email with ID:89 from noreply@smartplayer.org to sasha@ya.ru. Email status: success. Email transport: direct У команды еcть 4 параметра: --error, -e - вывести текст ошибок --message, -m - вывести текст сообщения --today, -t - вывести сообщения отправленные сегодня --limit N, -l N - вывести N сообщений. Нельзя вывести больше 50 записей, больше 20 записей с текстом сообщения и больше 30 записей с текстом ошибки.

Проверка доступности почтового сервера (через nslookup)

Команда для проверки с использованеим nslookup: nslookup -q=mx mariinsky.ru Ответ при доступности сервера, должен быть примерно:

andrey@workspace-cto:~$ nslookup -q=mx mariinsky.ru
Server:     127.0.0.53
Address:    127.0.0.53#53
Non-authoritative answer:
mariinsky.ru    mail exchanger = 10 mx3.mariinsky.ru.
mariinsky.ru    mail exchanger = 5 mx.mariinsky.ru.
mariinsky.ru    mail exchanger = 20 mx4.mariinsky.ru.
Authoritative answers can be found from:
andrey@workspace-cto:~$ 

Отдельное мини-приложение для отправки писем с официальных сайтов (smartplayer.ru/smartplayer.kz) под названием smartplayer-site-feedback-form

Данное приложение было разработано для отправки писем с официальных сайтов компании SmartPlayer и оно не является часть серверного приложения. Самодостаточное приложение которое выполняет одну функцию - отправку писем с сервера. Написано приложения по технологиям серверного приложения, т.е. NodeJS/PM2.

  • Репозиторий приложения: git@bitbucket.org:smartplayer/smartplayer-site-feedback-form.git
  • Функциональность приложения: Отправка писем через http://sendpulse.com
  • Технологии с которыми написано приложение: NodeJS
  • Технологии для отслеживания работоспособности приложения: PM2

Сборка приложения

1. Клонируем репозиторий git clone git@bitbucket.org:smartplayer/smartplayer-site-feedback-form.git 2. У проекта нет скрипта сборки, так что мы должны самостоятельно заархивировать папку и отправить её на целевой сервер где будем устанавливать данное приложение zip -r smartplayer-site-feedback-form_soft.zip smartplayer-site-feedback-form/ 3. На сервер создать учетную запись без root доступа, например sp-site adduser sp-site 4. Загрузить на сервер архив smartplayer-site-feedback-form_soft.zip любым удобным способом 5. Разархивировать архив в домашнюю директорию созданного пользователя на сервере в шаге 2, в нашем случае это будет unzip /tmp/smartplayer-site-feedback-form_soft.zip -d /home/sp-site/smartplayer-site-feedback-form 6. На сервере установить окружение NodeJS/PM2, как это сделать читайте файл README.md в репозитории приложения 7. Войти в разархивированную папку и установите зависимости необходимые для приложения cd /home/sp-site/smartplayer-site-feedback-form && npm install 8. Настройте конфигурацию приложения из файла примера (он скрытый), для это вначале скопируйте конфигурацию по умолчанию cp /home/sp-site/smartplayer-site-feedback-form/.env.example /home/sp-site/smartplayer-site-feedback-form/.env 9. Настройте конфигурацию приложения, пример конфигурации.

Specify application port
PORT=3400

# Feedback form endpoint
FEEDBACK_ENDPOINT=/

##################################################
# Database settings
##################################################
DB_HOST=localhost
DB_USER=
DB_PASSWORD=
DB_DATABASE=
DB_DIALECT=sqlite
DB_STORAGE=db.sqlite3

##################################################
# Email settings
##################################################
# required
EMAIL_FROM=noreply@smartplayer.org
# required
EMAIL_TO=sales@smartplayer.org
# default: 'Письмо с сайта smartplayer.ru'
EMAIL_SUBJECT=
# for connection to SMTP server
# default admin@smartplayer.org
EMAIL_LOGIN=admin@smartplayer.org
# required
EMAIL_PASSWORD=
#default smpt-pulse.com
EMAIL_HOST=
#default 465
EMAIL_PORT=
# defautl true
EMAIL_USE_TLS=

10. После того как настроили приложение запустите его и убедитесь что оно не перезапускается (pm2 list показывает, что uptime возрастает и приложение не перезапускается) pm2 start /home/sp-site/smartplayer-site-feedback-form/main.js 11.Сохраните изменения в конфигурации pm2 если все работает корректно pm2 save 12. Сделайте, так чтобы приложение запускалось автоматически после перезагрузке серверна физически pm2 startup 13. Далее необходимо настроить обратный проксе в веб сервере, в SmartPlayer всегда используется nginx, поэтому пример конфигурации (тут представлен полный файл конфигурации) представлена для него. Обратите внимание на /email/site/

upstream spformhandler {
  server localhost:3400;
}

#кеширование
proxy_cache_valid 1h;

proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=cache:30m max_size=1G;
proxy_temp_path /var/lib/nginx/proxy 1 2;
proxy_ignore_headers Expires Cache-Control;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;

server {	
	listen 80;
	listen 443;
	server_name www.smartplayer.kz;
	ssl_certificate /etc/ssl/smartplayer_kz_2022_2023.crt;
        ssl_certificate_key /etc/ssl/smartplayer_kz_2022_2023.key;
	return 301 $scheme://smartplayer.kz$request_uri;
	}

server {
        listen 80;
        server_name smartplayer.kz;
        return 301 https://smartplayer.kz$request_uri;
        }


server {
	listen 443 ssl;
	ssl_certificate /etc/ssl/smartplayer_kz_2022_2023.crt;
	ssl_certificate_key /etc/ssl/smartplayer_kz_2022_2023.key;
	server_name smartplayer.kz;
			
	root /var/www/smartplayer.kz;
	index index.html index.htm;

	# kill cache
	add_header Last-Modified $date_gmt;
        add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
        if_modified_since off;
        expires off;
        etag off;
	
	error_page 404 /404.html;

        location /prices{
                expires epoch;
                alias /var/www/smartplayer.kz/;
                index index.html;
        }

        location /feedback/ru/negative {
                expires epoch;
                alias /var/www/smartplayer.kz/;
                index index.html;
        }

        location /feedback/es/negative {
                expires epoch;
                alias /var/www/smartplayer.kz/;
                index index.html;
        }

        location /feedback/ru/positive{
                expires epoch;
                alias /var/www/smartplayer.kz/;
                index index.html;
        }

        location /feedback/es/positive{
                expires epoch;
                alias /var/www/smartplayer.kz/;
                index index.html;
        }

	location /bonus/{
                expires epoch;
		alias /var/www/smartplayer.ru/bonus/;
		index index.html;
	}

	location /bcs/{
		expires epoch;
		autoindex on;
		alias /var/www/smartplayer.ru/bcs/;
	}


	location /email/site/ {
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header Host $http_host;
		proxy_set_header X-NginX-Proxy true;

		proxy_pass http://spformhandler/;
		proxy_redirect off;

		proxy_http_version 1.1;
		proxy_set_header Upgrade $http_upgrade;
		proxy_set_header Connection "upgrade";

		proxy_connect_timeout 600;
		proxy_send_timeout 600;
		proxy_read_timeout 600;
		send_timeout 600;
	}
}

14. После настройки nginx обязательно запустите заново прочтение конфигурации nginx -s reload 15. Проверьте как отправляется письмо с сайта который вы устанавливали, должно быть сообщение вида Тут будет скрин 16. Перезагрузите сервер физически и заново попробуйте отпраивть тестовое письмо, все должно подняться автоматически без ручных действий с стороны системного администратора