Как отправлять письма используя Powershell Send-MailMessage


28 января 2021


Отправка писем через Powershel с Send-MailMessage

Для отправки писем в Powershell есть команда Send-MailMessage. С помощью этой команды мы можем выполнять отправку писем используя вложения, HTML формат и множеству получателей. У этой команды есть ряд особенностей, которые мы рассмотрим ниже на примерах.

 

Настройка SMTP сервера

Что бы вы смогли отправить письмо вы должны знать настройки для вашего сервера. Почтовые сервера, для отправки писем, используют протокол SMTP. Когда сервера SMTP общаются друг с другом они используют 25 порт, а клиент с сервером 465 или 587 порт. Кроме этого вы должны знать по какому адресу отвечает сервер и использует ли он шифрование. Обычно, если вы используете публичного провайдера, эти настройки доступны в документации.

Ниже пример настроек для яндекса:

  • smtp.yandex.com;
  • SSL;
  • 465.

Адрес сервера, в Powershel, можно указать двумя способами. Можно объявить используя специальную встроенную переменную $PSEmailServer:

$PSEmailServer = 'smtp.yandex.com'

Такая переменная будет работать в рамках одной сессии Powershell (до закрытия консоли) и нам не нужно будет указывать ее в каждой команде. Например так:

Send-MailMessage -SmtpServer 'smtp.yandex.ru'

Отмечу, что в случае яндекса и gmail знать логин/пароль и почтовый сервер не достаточно. В случае этих провайдеров, в их веб интерфейсах, понадобится настраивать специфические разрешения. В случае обычных, локальных серверов, этого обычно не требуется.

Порт сервера устанавливается в дополнительном параметре Port. Если он не указан, то будет использоваться порт по умолчанию - 25:

Send-MailMessage -SmtpServer 'smtp.yandex.ru' -Port 465

 

Аутентификация

Что бы мы могли отправить письмо - мы должны предоставить пару логин и пароль. Это можно сделать с помощью команды 'Get-Credential':

Send-MailMessage -SmtpServer 'smtp.yandex.ru' -Port 465 -Credential (Get-Credential)

Логин и пароль для отправки письма Powerhsell Send-MailMessage

Как видно на скриншоте - при каждом выполнении команды у нас появляется окно для ввода логина и пароля. Вы так же можете сохранить учетные данные в переменную и передавать ее в команды:

$cred = Get-Credentials
Send-MailMessage -SmtpServer 'smtp.yandex.ru' -Port 465 -Credential $cred

При работе с командой Get-Credential есть неочевидная деталь - ее запуск создает объект (логин и пароль) в памяти. Любая попытка его экспортировать (сохранить) приведет к шифрованию объекта ключем, индивидуальным для каждого пользователя. Т.е. это плохой вариант, если вы планируете отправлять письма со множества компьютеров - вам просто понадобится вводить эти данные у каждого пользователя.

Вы можете передать пароль обычным текстом, что решит проблему описанную выше:

$login = 'test@yandex.ru'
# Конвертируем пароль в защищенную строку
$password = 'password123' | ConvertTo-SecureString -AsPlainText -Force
# Создаем единый объект с логином и паролем
$cred = New-Object system.Management.Automation.PSCredential($login,$password)

Send-MailMessage -SmtpServer 'smtp.yandex.ru' -Port 465 -Credential $cred

Более подробно, про работу логинов и паролей в Powershell, описывалось в предыдущих статьях.


Отправка писем

Разобравшись с предыдущими параметрами мы можем отправить письмо. Дополнительно мы должны указать следующие параметры:

  • UseSsl - так как наше подключение шифруется;
  • From - ящик, с которого отправляется письмо;
  • To - кому отправляем;
  • Subject - тема письма;
  • Body - содержание письма.

В моем случае команда будет выглядеть так:

​$PSEmailServer = 'smtp.yandex.com'
$cred = Get-Credential
Send-MailMessage -Port 465 `
-From 'test@yandex.ru' `
-To 'test@yandex.ru' `
-Subject 'Тема письма' `
-Body 'Текст письма' `
-UseSsl `
-Credential $cred

Данная команда, в случая yandex и многих других, публичных, провайдеров вернет ошибку:

  • Send-MailMessage : Не удается прочитать данные из транспортного соединения: net_io_connectionclosed.

Эта проблема связана с тем, что библиотека .NET SmtpClient, которая работает с командой Send-MailMessage, может использовать шифрование SSL/TLS только с поддержкой STARTTLS. Стандарт STARTTLS расширял возможности шифрования и должен был стать массовым, но этого не случилось (и скорее всего не случится). Во время публикации стандарта STARTTLS был объявлен новый порт для SMTP - 587(msa), а порт 465 (smtps) объявили устаревшим. Так как новый стандарт так и не приобрел массовость провайдеры, чаще всего, пишут только про 465 порт, но и 587 так же у многих провайдеров работает.

Подводя коротко итог предыдущего абзаца, если провайдер пишет про 465 порт, а он не работает - попробуйте 587. В случае с яндексом это именно так.

Так же, если вам нужно что бы у получателя выводилось ваше имя/название компании, используйте следующий формат во From:

-From 'Александр Мельников <test@yandex.ru>'

Несколько адресатов

Так же как и в случае обычного почтового клиента мы можем отправлять письма нескольким адресатам используя:

  • To - обычный получатель;
  • Cc - получатель копии;
  • Bcc - получатель скрытой копии.

Если планируется использовать несколько почтовых ящиков, в одном параметре, разделяйте их запятыми:

​$PSEmailServer = 'smtp.yandex.com'
$cred = Get-Credential
Send-MailMessage -Port 465 `
-From 'test@yandex.ru' `
-To 'test1@yandex.ru', 'test2@yandex.ru', `
-Bcc 'test3@yandex.ru', `
-Subject 'Тема письма' `
-Body 'Текст письма' `
-UseSsl `
-Credential $cred

Кодировка

Как вы знаете Windows пока не перевела работу ОС на UTF8 (используется ANSI и ASCII). В это же время UTF8 является стандартом для работы в интернете. По этой причине, если вы не укажете кодировку, то может получится следующая картина:

Отправка письма с Powershell Send-MailMessage в верной кодировке

Отмечу, что это проблема возникнет в Powershell 5.1, которая установлена по умолчанию в Windows. В случае с Powershell 7.1, по умолчанию используется UTF8. Тем не менее вы можете установить свое значение:

  • ASCII;
  • BigEndianUnicode;
  • Default;
  • OEM;
  • Unicode;
  • UTF7;
  • UTF8;
  • UTF32.

Значения устанавливаются в параметре Encoding:

​$PSEmailServer = 'smtp.yandex.com'
$cred = Get-Credential
Send-MailMessage -Port 465 `
-From 'test@yandex.ru' `
-To 'test1@yandex.ru', 'test2@yandex.ru', `
-Bcc 'test3@yandex.ru', `
-Subject 'Тема сообщения' `
-Body 'Текст письма' `
-UseSsl `
-Credential $cred `
-Encoding 'UTF8'

Отправка письма с разметкой HTML

Письма могут быть посланы как обычный текст или с HTML разметкой. Для разметки дополнительно к параметру Body нужно указать BodyAsHtml:

$body = '
<table style="width:100%">
  <tr>
    <th>Размер диска</th>
    <th>100Мб</th> 
    <th>200Мб</th>
  </tr>
</table>
'

​$PSEmailServer = 'smtp.yandex.com'
$cred = Get-Credential
Send-MailMessage -Port 465 `
-From 'test@yandex.ru' `
-To 'test1@yandex.ru' `
-Subject 'Тема сообщения' `
-Body $body `
-BodyAsHtml `
-UseSsl `
-Credential $cred `
-Encoding 'UTF8'

Отправка HTML письма через Powershell Send-MailMessage

Вложения

Вложения можно перечислить используя параметр Attachments и пути до файлов:

Send-MailMessage -Port 465 `
-From 'test@yandex.ru' `
-To 'test1@yandex.ru' `
-Subject 'Тема письма' `
-Body $body `
-UseSsl `
-Credential $cred `
-Encoding 'UTF8' `
-Attachments 'C:\pic1.jpg','C:\pic2.jpg'

Этот параметр так же принимает значения через конвейер т.е. мы можем получить все файлы в папке и отправить их:

Get-ChildItem -Path 'C:\Docs' | Send-MailMessage -Port 465 `
-From 'test@domain.local' `
-To 'test1@domain.local' `
-Subject 'Тема сообщения' `
-Body $body `
-UseSsl `
-Credential $cred `
-Encoding 'UTF8'

Уведомления о доставке

Мы можем получить уведомления, если установим следующие параметры у -DeliveryNotificationsOptions:

  • OnSuccess - при успешной доставке;
  • OnFailure - если сообщение не доставлено;
  • Delay - при задержке SMTP сервером.

Через запятую их можно установить несколько:

Send-MailMessage -Port 465 `
-From 'test@domain.local' `
-To 'test1@domain.local' `
-Subject 'Тема' `
-Body $body `
-UseSsl `
-DeliveryNotificationsOptions 'OnSuccess', 'OnFailure'

Уведомление будет доставлено на почтовый ящик.

Приоритет

Вы можете установить приоритет, который увидит получатель письма. Отмечу, что такой приоритет отображается не во всех клиентах. Приоритет определяется в параметре Priority со значениями:

  • Normal (по умолчанию)
  • High
  • Low

...

Теги: #powershell


Каналы
Telegram FixMyPc Telegram Лента FixMyPC RSS Rss
Популярные тэги
О блоге
Этот блог представляет собой конспекты выученного материала, преобретенного опыта и лучшие практики в системном администрировании и программировании.