Встроенный командлет Send-MailMessage можно использовать для отправки email писем из PowerShell. Данный встроенный командлет доступен для отправки почтовых email сообщений в PowerShell начиная с версии 2.0 (командлет применяется вместо класса .Net System.Net.Mail). Send-MailMessage позволяет отправить через SMTP сервер письма с вложениями, использовать HTML формат для тела письма, включить уведомления о доставке, отправить письмо сразу нескольким получателям и т.д. В этой статье мы рассмотрим, как использовать Send-MailMessage для отправки email сообщений из ваших скриптов PowerShell.
Для получения базовой информации о синтаксисе командлета, выполните команду:
get-help Send-MailMessage
Send-MailMessage [-To] <String[]> [-Subject] <String> [[-Body] <String>] [[-SmtpServer] <String>] [-Attachments <String[]>] [-Bcc <String[]>] [-BodyAsHtml] [-Cc <String[]>] [-Credential <PSCredential>] [-DeliveryNotificationOption {None | OnSuccess | OnFailure | Delay | Never}] [-Encoding <Encoding>] -From <String> [-Port <Int32>] [-Priority {Normal | Low | High}] [-UseSsl] [<CommonParameters>]
Основные параметры:
- From – адрес отправителя если SMTP сервер не проверяет адрес отправителя, то можно отправить письмо от имени любого email адреса);
- To – email адрес получателя;
- SMTPServer – адрес SMTP сервера , через который нужно выполнить отправку письма
Адрес SMTP сервера не обязательно указывать, если вы задали адрес почтового сервера в переменной окружения $PSEmailServer:
$PSEmailServer = "smtp.winitpro.ru"
Отправка письма из консоли PowerShell с помощью командлета Send-MailMessage
Следующая команда PowerShell отправит письмо с указанной темой (Subject) и содержимым (Body) нескольким получателям.
Send-MailMessage -From '[email protected]' -To '[email protected]','[email protected]' -Subject "Alert from Server1" -Body "It is email body" –SmtpServer 'smtp.winitpro.ru'
Для удобства редактирования предыдущую команду отправки можно представить так:
Send-MailMessage `
-SmtpServer smtp.winitpro.ru `
-To '[email protected]','[email protected]' `
-From '[email protected]' `
-Subject "test" `
-Body "Тема письма на русском" `
-Encoding 'UTF8'
Обратите, что в последней команде мы дополнительно указали, что нужно использовать для письма кодировку UTF8. Иначе, если тема или текст письма будут содержать русские буквы, то они будут отображены знаками вопроса.
Вы можете задать нескольких получателей с помощью параметров:
-
To
— обычные получатели; -
Cc
– получатели копии письма; -
Bcc
— получатели скрытой копии.
Вы можете включить для письма уведомление о доставке с помощью параметра -DeliveryNotificationOption. Возможные значения:
- OnSuccess (отчет при удачной доставке);
- OnFailure (отчет если доставка не выполнена);
- Delay (оповестить, если доставка отложена).
В одной команде можно указать сразу несколько опций:
Send-MailMessage … -DeliveryNotificationsOptions 'OnSuccess', 'OnFailure'
Уведомление о доставки будет отправлено в почтовый ящик, указанный в поле -From.
Также вы можете задать приоритет письма (отображается не во всех клиентах):
-Priority High|Low|Normal
Если нужно добавить в письмо вложение, используйте параметр -Attachments. В следующем примере мы отправим письмо в формате HTML (параметр -BodyAsHtml) и прикрепим к письму файлы report1.txt и report2.txt с локального диска:
$MailMessage = @{
To = "[email protected]
Bcc = "[email protected]", "[email protected]"
From = "DC server <[email protected]>"
Subject = "Отчет с сервера DC"
Body = "<h1>Добро пожаловать!</h1> <p><strong>Сформировано:</strong> $(Get-Date -Format g)</p>”
Smtpserver = "smtp.winitpro.ru"
Port = 25
UseSsl = $false
BodyAsHtml = $true
Encoding = “UTF8”
Attachment = “C:\ps\report1.txt”, “C:\ps\report2.txt”
}
Send-MailMessage @MailMessage -Credential $cred
В этом примере мы также заменили Display Name у получателя на “DC server”.
Вот как выглядит это письмо с HTML форматированием и вложениями в интерфейсе Outlook.
Set-Mailbox sharedmailbox -MessageCopyForSentAsEnabled $True
SMTP аутентификация и TLS/SSL шифрование в команде Send-MailMessage
По умолчанию командлет Send-MailMessage выполняет отправку письма через стандартный SMTP порт TCP 25. Если ваш SMTP сервер позволяет отправить письмо только по защищенному протоколу, нужно указать номер порта в атрибуте –Port (чаще всего это 465 или 587) и опцию UseSsl:
-SmtpServer 'smtp.winitpro.ru' -Port 465 –UseSsl
Если SSL сертификат SMTP сервера не соответствует FQDN, указанному в HELO то появится ошибка:
Send-MailMessage: The remote certificate is invalid according to the validation procedure.
При отправке письма с помощью шифрования SSL/TLS также может появится ошибка:
Send-MailMessage : Unable to read data from the transport connection: net_io_connectionclosed
В этом случае рекомендуется проверить
- Что указанный порт доступен:
Test-NetConnection -winitpro.ru –Port 465
- Попробуйте использовать другой SMTP порт. Например, 587 (msa) вместо 465 (smtps). Порт 587 является стандартным при использовании расширения STARTTLS.
- Если у вас используется старая версий ОС (Windows Server 2012/Windows 8 и ниже), нужно включить поддержку протокола TLS2 для PowerShell с помощью команды:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Название | Адрес SMTP сервера | Порт | Тип шифрования |
Yandex | smtp.yandex.ru | 465 | TLS/SSL |
Mail.ru | smtp.mail.ru | 465 | TLS/SSL |
Gmail | smtp.gmail.com | 587 25 465 | TLS TLS SSL |
Office 365 | smtp.office365.com | 587 | TLS |
Outlook.com | smtp-mail.outlook.com | 587 | TLS |
Если SMTP сервер запрещает анонимную отправку (запрещен relay), то при попытке отправить письмо вы получите ошибку:
5.7.1 Client was not authenticated.
Или:
The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.57 SMTP; Client was not authenticated to send anonymous mail during MAIL FROM.
В этом случае вы можете аутентифицироваться на SMTP сервере с помощью параметра –Credential.
Можно интерактивно запросить данные пользователя для аутентификации
Send-MailMessage …… -Credential (Get-Credential)
Или вы можете сохранить имя пользователя и пароль для аутентификации на SMTP через переменную:
$cred = Get-Credential
Send-MailMessage ... -Credential $cred
PowerShell: отправка письма через Gmail/Mail.ru/Яндекс
Для отправки письма через ваш ящик на одном из публичных почтовых сервисов вместо пароля для входа в ящик рекомендуется использовать App Password. Например, в Gmail вы можете создать App Password после того, как настроите 2 факторную аутентификацию для вашего аккаунта Google. Сгенерируйте и скопируйте ваш App password (в google это пароль из 16 символов).
Следующий пример показывает, как отправить письмо из PowerShell из вашего ящика Google. Вместо пароля вашего аккаунта нужно использовать App Password. В этом примере мы сохраним пароль для подключения к SMTP серверу непосредственно в коде скрипта PowerShell.
$From = "[email protected]"
$To = "[email protected]"
$Subject = "Test message subject from $($env:computername)"
$Body = "Email text"
$Password = "yourgoogleapppassword" | ConvertTo-SecureString -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $From, $Password
Send-MailMessage -From $From -To $To -Subject $Subject -Body $Body -SmtpServer "smtp.gmail.com" -port 587 -UseSsl -Credential $Credential
При использовании команды Send-MailMessage в новых версиях PowerShell Core 7.x появляется предупреждение:
WARNING: The command 'Send-MailMessage' is obsolete. This cmdlet does not guarantee secure connections to SMTP servers. While there is no immediate replacement available in PowerShell, we recommend you do not use Send-MailMessage at this time. See https://aka.ms/SendMailMessage for more information.
Командлет Send-MailMessage использует .NET класс SmtpClient для отправки писем, которые не поддерживает современные методы проверки подлинности, в том числе Microsoft Modern Authentication. В Microsoft 365/Exchange Online для отправки писем из PowerShell рекомендуется использовать Graph API, например, командлет
Send-MgUserMai
l или
Invoke-RestMethod
для вызова метода sendMail в REST API (подробнее в статье PowerShell: Отправка писем через Microsoft Graph API).
А так не проще? И без VBS
Send-MailMessage -From user@domain -To user_@domain_ -SmtpServer server_name(/ip) -Subject «Subject» -Body «text»;
А как файл *.eml преобразовать в почтовое сообщение с помощью powershell ? Или чем еще?
Впрямую преобразовать eml в текст — даже не знаю как. Если только открыть его как текстовый файл и распарсить по полям. Или какой-то вариант отправки файла через Outlook скриптом powershell. Но готового к сожалению нет.
Не проще ли вложением отправлять или сохранить его в виде html, получить содержимое через get-content и отправить через Send-MailMessage как в статье?
У нас контора странная: через шлюз почтовые сообщения можно только файлами. Поэтому думаю над таким вариантом: поставить SMTP сервер, смотрящий в «никуда». В исходящей очереди у него, по-моему, копятся eml файлы. Их и отправлять через шлюз. Спасибо за варианты!
В другой Вашей статье (про SMTP-сервер) прочитал, что файл можно положить в папку Pickup.
Попробовал файл .eml (из папки очереди) из одного SMTP сервера положить в папку Pickup другого SMTP-сервера (с другой стороны шлюза). Сработало, тот сервер отправил файл, пришло письмо, русские символы нормальные!
ну да, решение довольно странное, а архитектура похожа на происки безопасников в погонах … 🙂
Привет, не подскажете, как можно отправить сообщение с почтового аккаунта с 2-факторной аутентификацией?
Сгенерируйте app password (в том же gmail и microsoft это есть) и исопльзуйте это пароль для отправки письма
Здравствуйте!
При отправке с Low priority письмо приходит со следующими заголовками:
X-Priority: 5
Priority: non-urgent
Importance: low
Thunderbird почему-то неправильно их воспринимает и отображает High priority.
Для теста отправил письмо из Thunderbird с Low priority, отобразилось корректно, но заголовки следующие:
X-Priority: 4 (Low)
Либо
X-Priority: 5 (Lowest)
, который соответствует Lowest priority и т.п.Есть возможность их как-то подружить?
Как в тему\тело письма поместить переменную?. Образно говоря хочется знать о каком сервере идет речь в письме.
У меня так реализовано:
$BodyTxt1 = 'текст'
$BodyTxt2 = 'еще текст'
$EmailBody = $BodyTxt1, $some_var, $BodyTxt2 -join ' '
Send-MailMessage -Body $EmailBody
Команду сократил для понимания принципа.
Разобрался. Знающим врятли пригодится, но вдруг новичкам подойдет) Изменил синтаксиси с $env:computername на $($env:computername)
Есть возможность забирать почту с ящика с помощью powershell?
Подскажите пожалуйста.
Есть возможность установить «флажок» у письма или сделать «красную» категорию письма ?
Категорию — нет, эта функция Outlook. Можно только поставить приоритет, добавив:
-Priority High
Добрый день.
Подскажите, есть возможность разрешить для всех или же наоборот запретить даже для администраторов отправку от имени чужого п/я?
Это зависит от почтовой системы, которую вы используете для отправки писем. В Exchnage можно разрешить отправку другим пользователям на уровне каждого ящика.
Постоянно ловлю ошибку «Send-MailMessage : Время ожидания операции истекло.»
Код:
$password = ConvertTo-SecureString "password" -AsPlainText -Force
Send-MailMessage -From '[email protected]' -To '[email protected]' -Subject "test" -Body "body" –SmtpServer 'smtp.yandex.ru' -Encoding 'UTF8' -port 465 -UseSsl -Credential (New-Object System.Management.Automation.PSCredential('login', $password))
В чём может быть проблема?
(порт на 587 менял, правильность кредов проверял)
1) Проверить, что порт отвечает:
tnc smtp.yandex.ru -port 465
2) Вы используете пароль приложения для ящика яндекс (_https://yandex.ru/support/id/authorization/app-passwords.html)? я не помню, позволяюет ли он для smtp использовать реальный парлоль. скорее всего нет.
Такая же ситуация
Порт 465 проверял, доступен, пароль приложения ссгенерирован. В чем может быть еще ошибка?
# Password
$pwd_1=»***********»
# Secure Password
$pwd_2=ConvertTo-SecureString $pwd_1 -AsPlainText -force
# Email account to send mail
$sendmbx=»[email protected]»
# Email account to recive mail
$recivembx=»[email protected]»
# Body
$body=»This is a test mail from power shell»
# Properties
$props=@{
SMTPServer=»smtp.yandex.ru»
From=$Sendmbx
To=$recivembx
UseSSL=$true
Port=465
Subject=»Test mail from PowerShell»
Credential=New-Object System.Management.Automation.PSCredential($sendmbx, $pwd_2)
}
Send-MailMessage @props $body
Заработало на 25 порту
Может, кому пригодится. У коммандлета «Send-MailMessage» есть недостаток — если надо пройти SMTP-аутентификацию, он требует явного указания учётных данных, использовать интегрированную аутентификацию (т.е. учётные данные пользователя, под которым запущен), он не умеет. Возникает вопрос, где и как хранить пароль — делать это прямо в тексте скрипта весьма не здорово, передавать как параметр запуска скрипта тоже.
Для решения проблемы можно вместо коммандлета отправлять сообщение, используя объекты .Net классов System.Net.Mail.MailMessage и System.Net.Mail.SmtpClient — тогда у объекта SmtpClient можно включить свойство UseDefaultCredentials, и он сам пройдёт аутентификацию, как текущий пользователь.
Это весьма удобно, например, если надо запускать скрипт, отправляющий сообщения, при помощи планировщика (Task Scheduler) — можно не заботиться вопросом хранения пароля, вместо этого просто создаём задание, запускающееся из-под нужного пользователя и в процессе сохранения задания один раз указываем его пароль, после чего планировщик сам сохранит его в Protected Storage.