Отправка e-mail из скриптов
На данной странице рассматриваются различные способы правильной отправки почтовых сообщений, содержащих не-ASCII символы в тексте и вложениях.
Скрипты всевозможных форумов обычно не рассчитаны на язык, отличный от английского, и при использовании их с русским языком генерируют неправильные сообщения. Большинство почтовых клиентов научились понимать неправильно сформированные письма, но далеко не все, и тем более не все виды ошибок. Подводные камни могут поджидать где угодно, да и лучше делать программы, формирующие письма в соответствии со стандартами. Советы, данные здесь, помогут вам отправлять правильные письма на любом языке. Если вы увидели здесь несоответствие с каким-либо RFC — правьте смело, либо пишите на страницу обсуждения.
[править] Теория
[править] Кодировка
В заголовке письма допускаются только ASCII символы, поэтому строка, содержащая не-ASCII символы (например, русские буквы), должна быть закодирована.
В теле письма можно использовать 8 битные (не-ASCII) символы, правда с некоторыми ограничениями (максимальная длина строки, ?). Поэтому чтобы передать не-ASCII текст в неизменном виде, его лучше закодировать.
Прикрепляемые файлы (mime, attach) необходимо кодировать в base64, чтобы они были получены неизменными.
[править] Адрес отправителя
Ни в коем случае нельзя указывать e-mail клиента, в адресе отправителя, так как часто такие письма будут уходить в «Спам» или вообще удаляться, из-за действия SPF. Правильно отправителем указывать сам сервер, например robot@example.com, а в поле «Reply-to» можно указать адрес клиента. Тогда, получив письмо, человек может нажать «ответить» и таким образом напишет клиенту.
P.S.: в GMail, если адрес из поля «From» есть в списке адресов «Send mail as», то поле «Reply-to» будет игнорироваться при нажатии на кнопку «Ответить». Посмотреть список этих адресов можно по ссылке: https://mail.google.com/mail/#settings/accounts
[править] RFC
[править] Скрипты
[править] Отправка в Perl
Нам понадобятся модули MIME::Base64 и Encode, входящие в стандартную поставку Perl («Core modules»).
Для кодирования заголовков письма (тема, отправитель, получатель) будем использовать функцию encode модуля Encode. У неё есть специальный режим для кодирования заголовков писем, при этом он принимает только utf-8.
Итак, подключаем модуль и кодируем: use Encode qw/encode decode/; my $Mail_subject = encode(‘MIME-Header’, decode(‘utf8’, ‘Тестовая тема’)); my $Mail_from = encode(‘MIME-Header’, decode(‘utf8’, ‘Тестовый Отправитель ‘)); my $Mail_to = encode(‘MIME-Header’, decode(‘utf8’, ‘Тестовый Получатель ‘));
Следует отметить использование функции decode для приведения текста к кодировке utf-8. Даже если текст вашего скрипта уже в utf-8, вам всё равно придётся вызвать функцию decode. Об этом написано здесь:
CAVEAT: When you run $string = decode("utf8", $octets), then $string may not be equal to $octets. Though they both contain the same data, the UTF8 flag for $string is on unless $octets entirely consists of ASCII data (or EBCDIC on EBCDIC machines). See «The UTF8 flag» below.
[править] С помощью Mail::Sendmail
В руководстве указано, что модуль сам добавит указанные заголовки, если они не будут заданы
Mime-Version: 1.0 Content-Type: 'text/plain; charset="iso-8859-1"' Content-Transfer-Encoding: quoted-printable or (if MIME::QuotedPrint not installed) Content-Transfer-Encoding: 8bit Date: [string returned by time_to_date()]
[править] С помощью MIME::Lite
Раздел не написан.
[править] Отправка в PHP
$headers = "Reply-To: от_чьего_имени_отправить\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: сколько_битная_кодировка_текста_письмаbit\r\nContent-type: text/plane; charset=кодировка_контента_письма\r\n"; $sublectMail = "=?кодировка_контента_письма?B?".base64_encode(Тема_письма)."?=\r\n"; mail(кому_отослать,$sublectMail,$message,$headers);
$headers="Reply-To: $model->email\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 8bit\r\nContent-type: text/plane; charset=UTF-8\r\n"; $sublectMail = "=?UTF-8?B?".base64_encode('Вопрос от '.$model->name)."?=\r\n"; $messageMail = $model->body; mail($params['adminEmail'],$sublectMail,$messageMail,$headers);
[править] Отправка в Python
С использованием библиотеки smtplib
import smtplib from email.mime.text import MIMEText me = 'admin@mail.ru' you = 'kot_smit@mail.ru' smtp_server = 'smtp.mail.ru' msg = MIMEText('Message e-mail') msg['Subject'] = 'The contents of ' msg['From'] = me msg['To'] = you s = smtplib.SMTP(smtp_server) s.sendmail(me, [you], msg.as_string()) s.quit()
[править] Отправка из оболочки командной строки
[править] С помощью sendmail
Файл /usr/bin/sendmail многие почтовые программы (в частности, Exim4) ставят алиасом на себя, обрабатывая отправку почты, и принимая большинство флагов sendmail
Включение сендмайла для отправки (Для FreeBSD):
# строка в /etc/rc.conf ##### SENDMAIL_ENABLE="NO" # Комментарий: NO - только для отсылки, NONE - отключить полностью # После чего перезагрузиться или запусить вручную под рутом: /etc/rc.d/sendmail restart
Отправка сообщения из файла FILE.eml (формат — обычное сообщение почты, RFC 822):
(проверена работа во FreeBSD от 5 до 8 (sendmail из комплекта поставки), и Debian 6 (стандартный симлинк с sendmail на exim4)):
COMMAND cat FILE.eml | /usr/sbin/sendmail -t -f fromuser@domain.ru где -t -- считывать адреса доставки из заголовков письма -f fromuser@domain.ru -- использовать этот обратный адрес в SMTP-сессии FILE.eml -- файл или эквивалентный сгенерированный вывод, должен быть (между дефисами): ------------------------- From: fromuser@fromdomain.ru To: touser1@domain.ru, touser2@domain.ru, touser3@domain.ru Subject: Email from server (FreeBSD, Debian) text text Пустая строка после заголовков обязательна! Также можно добавлять другие необходимые заголовки. text text Возможны русские буквы (составлять в KOI8-R, это кодировка по-умолчанию для почтовых клиентов. Либо использовать любую кодировку, с указанием соотв. заголовка. text text --------------------------
[править] С помощью mutt
Mutt является консольным почтовым клиентом (POP3, IMAP), одним из самых мощных. Также им удобно отправлять письма с вложениями из командной строки
Нужно учитывать, что mutt по умолчанию сам только генерирует письмо, для отравки он запускает sendmail или эквивалент (настраивается) примерно таким же образом, что и в предыдущем пункте.
Чтобы mutt отправлял сообщения по SMTP самостоятельно (в том числе с авторизацией, на другой порт и т.п.), необходимо указывать параметр «set smtp_url=smtp://smtp.domain.com/» в конфигурационном файле /etc/Muttrc или в командной строке.
В отличие от sendmail, клиент mutt делает перекодировку русских названий (темы, адресов). Тип (Content-type) вложения (по которому получившие письмо почтовые клиенты понимают, как правильно обрабатывать вложенный файл) mutt устанавливает по расширению файла-вложения, в соответствии с системным файлом /etc/mime.types (для Debian).
Так, чтобы вложение понималось почтовым клиентом именно вложенным письмом, а не текстом, файл вложения для mutt должен иметь расширение .eml (Content-type=message/rfc822).
%$ cat message | mutt -x -a file.jpg -s "тема" address@host.net
Отправляется сообщение из файла message по адресу address@host.net. К письму прикрепляется файл file.jpg. Обратный адрес и прочие атрибуты письма могут браться из конфигурационного файла ~/.muttrc или формироваться автоматически.
Более подробный синтаксис:
%$ cat message.txt | mutt -e 'set from="Name From "' -e 'set envelope_from=yes' -a file.1 -a file.2 -s 'Subject' to@email.ru где: -a -- вкладываемые файлы (может быть несколько) -e -- параметры в командной строке, используемые в muttrc (может быть несколько) from -- обратный адрес в письме (по умолчанию текущий_пользователь@имя_системы) envelope_from -- если "yes", в параметры обратного адреса для SMTP передаётся обратный адрес из "from", (не работает со старыми версиями sendmail) Реальный пример, debian 6 -- отправить текст из файла body.txt и вложением все файлы-письма по маске *.eml: $/usr/bin/mutt -x -e 'set from=from@email.ru' -s 'Subject email' to@email.ru -a *.eml < body.txt
[править] С помощью mpack
Mpack - старая программа (Linux, FreeBSD), предназначенная для упаковывания файла в MIME-формат.
Если в качестве выхода указать емейл (или несколько), файл будет отправлен с помощью sendmail или его заменителя.
Особенности - вложить в письмо можно только один файл, но есть опция максимального размера, если он превышается, генерируется несколько выходных файлов (писем).
mpack [ -s subject ] [ -d descriptionfile ] [ -m maxsize ] [ -c content-type ] file address . mpack [ -s subject ] [ -d descriptionfile ] [ -m maxsize ] [ -c content-type ] -o outputfile file
[править] С помощью biabam
Biabam не умеет правильно кодировать русский текст при отправке. Если вы знаете, как это исправить — напишите здесь.
Данная программа использует штатный клиент mail.
%$ cat message | biabam file.jpg -s "тема" address@host.net
Отправляется сообщение из файла message по адресу address@host.net. К письму прикрепляется файл file.jpg. Обратный адрес и прочие атрибуты письма могут браться из конфигурационного файла ~/.mailrc.
[править] Ссылки
- Отправка писем с авторизацией на SMTP-сервере из Perl (рус.) — в ней так же учитывается перекодирование заголовков и тела письма.
- Грамотная настройка сервера отправки почты для скриптов PHP (рус.)
- Как грамотно отправлять почту из скриптов (в частности — на PHP) (рус.)
- Unicode and e-mail (англ.) статья на английской wikipedia.
[править] Лицензия на текст
Текст доступен на условиях лицензии Creative Commons Attribution/Share-Alike
[править] Материалы по настройке почтовых систем на Xgu.ru
- Sendmail
- Борьба со спамом в Sendmail
- Использование ClamAV, SpamAssassin, MIMEDefang для борьбы с нежелательной почтой в Sendmail
- Переход с POP3 на IMAP4
- Копирование исходящей почты с помощью Sendmail
- Отправка e-mail из скриптов
- Cyrus IMAP Server
Sending MIME multipart message with Send-mailmessage
You can employ the .NET System.Net.Mail.MailMessage class for constructing and transmitting an email together with inline images.
Here's an illustration:
# Variables $smtpServer = "smtp.yourserver.com" $smtpPort = 587 $emailFrom = "[email protected]" $emailTo = "[email protected]" $subject = "Subject Text" $body = @" This is an example email that includes an inline image.
"@ $smtpUser = "smtpUser" $smtpPass = "smtpPassword" $imagePath = "C:\path\to\your\image.jpg" # Create a new MailMessage object $message = New-Object System.Net.Mail.MailMessage $message.From = $emailFrom $message.To.Add($emailTo) $message.Subject = $subject $message.IsBodyHtml = $true $message.Body = $body # Create a new Attachment object for the inline image $attachment = New-Object System.Net.Mail.Attachment -ArgumentList $imagePath $attachment.ContentDisposition.Inline = $true $attachment.ContentDisposition.DispositionType = "Inline" $attachment.ContentId = "MyInlineImage" $message.Attachments.Add($attachment) # Create a new SmtpClient object and send the email $smtp = New-Object System.Net.Mail.SmtpClient($smtpServer, $smtpPort) $smtp.EnableSsl = $true $smtp.Credentials = New-Object System.Net.NetworkCredential($smtpUser, $smtpPass) $smtp.Send($message) # Clean up $message.Dispose() $attachment.Dispose()
This script will dispatch an email alongside the image as an inline attachment. The img element within the HTML body references the ContentId of the attachment, which renders the image exhibit inline within the email body.
This script moreover presumes that you require authenticating alongside the SMTP server. If you don't necessitate authentication, you can eliminate the line that establishes the Credentials property.
Отправка HTML-письма с изображениями с помощью email.mime python
Дано: HTML - файл с привязанными к нему картинками, которые лежат в той же директории. Надо: отправить письмо так, чтобы оно отображалось у получателя как HTML-страница с картинками на своём месте. Что я пытался делать: У меня есть код python, который отправляет HTML, но у получателя вместо картинок просто прямоугольники с красными крестиками (нет картинок). Вот мой код:
import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase from email.header import Header def mail_sender(recip, subj, text): DEFAULT_SMTP_SERVER = '. ' SENDER = '. ' RECIPIENT = recip RECIPIENT2 = '. ' msg = MIMEMultipart('alternative') msg['From'] = SENDER msg['To'] = RECIPIENT msg['Bcc'] = RECIPIENT2 sub_hed = subj msg['Subject'] = Header(sub_hed, 'utf-8').encode() msg.attach(MIMEText(text, 'plain')) msg.attach(MIMEText(text, 'html')) message = msg.as_string() server = smtplib.SMTP(DEFAULT_SMTP_SERVER) server.sendmail(SENDER, [RECIPIENT], message) server.sendmail(SENDER, [RECIPIENT2], message) server.quit() f = open('TestHTML.html', 'r') result = f.read() mail_sender('[email protected]', 'тест', result)
ВОПРОС: Как сделать так, чтобы получатель видел полноценный HTML-шаблон с картинками? Может быть, подход неправильный или что-то надо изменить в коде?
Отслеживать
1,085 7 7 серебряных знаков 25 25 бронзовых знаков
Работа с e-mail
Laravel предоставляет простой интерфейс к популярной библиотеке SwiftMailer. Главный файл настроек - app/config/mail.php - содержит всевозможные параметры, позволяющие вам менять SMTP-сервер, порт, логин, пароль, а также устанавливать глобальный адрес from для исходящих сообщений. Вы можете использовать любой SMTP-сервер, либо стандартную функцию PHP mail - для этого установите параметр driver в значение mail . Кроме того, доступен драйвер sendmail .
Отправка через API
Laravel содержит драйвера отправки почты через HTTP API сервисов Mailgun и Mandrill. Отправка через API как правило работает быстрее, чем отправка через протокол SMTP. Оба этих драйвера требуют наличия пакета Guzzle для осуществления HTTP-запросов. Чтобы включить его в свое приложение, добавьте в composer.json
"guzzlehttp/guzzle": "~4.0"
composer update
Драйвер Mailgun
В файле app/config/mail.php установите опцию driver в 'mailgun'. Создайте файл app/config/services.php , в котором укажите данные вашего аккаунта на mailgun.com :
'mailgun' => array( 'domain' => 'your-mailgun-domain', 'secret' => 'your-mailgun-key', ),
Драйвер Mandrill
В файле app/config/mail.php установите опцию driver в 'mandrill'. Создайте файл app/config/services.php , в котором укажите данные вашего аккаунта на mandrill.com :
'mandrill' => array( 'secret' => 'your-mandrill-key', ),
Log Driver
Если в файле app/config/mail.php установить опцию driver в 'log', то все отправляемые письма будут записываться в лог-файл фреймворка и не будут рассылаться. Этот вариант используется для отладки.
Основы использования
Метод Mail::send используется для отправки сообщения:
Mail::send('emails.welcome', array('key' => 'value'), function($message) < $message->to('foo@example.com', 'Джон Смит')->subject('Привет!'); >);
Первый параметр - имя шаблона, который должен использоваться для текста сообщения. Второй - ассоциативный массив переменных, передаваемых в шаблон. Третий - функция-замыкание, позволяющая вам внести дополнительные настройки в сообщение.
Примечание: Переменная $message всегда передаётся в ваш шаблон и позволяет вам прикреплять вложения. Таким образом, вам не стоит передавать одноимённую переменную в массиве $data .
В дополнение к шаблону в формате HTML вы можете указать текстовый шаблон письма:
Mail::send(array('html.view', 'text.view'), $data, $callback);
Вы также можете оставить только один формат, передав массив с ключом html или text :
Mail::send(array('text' => 'view'), $data, $callback);
Вы можете указывать другие настройки для сообщения, например, копии или вложения:
Mail::send('emails.welcome', $data, function($message) < $message->from('us@example.com', 'Laravel'); $message->to('foo@example.com')->cc('bar@example.com'); $message->attach($pathToFile); >);
При добавлении файлов можно указывать их MIME-тип и/или отображаемое имя:
$message->attach($pathToFile, array('as' => $display, 'mime' => $mime));
Если вам надо просто отправить письмом несколько слов, то вместо того, чтобы создавать для этого шаблон, воспользуйтесь простым методом raw :
Mail::raw('Текст письма', function($message) < $message->from('us@example.com', 'Laravel'); $message->to('foo@example.com')->cc('bar@example.com'); >);
Примечание: Объект $message, передаваемый функции-замыканию метода Mail::send , наследует класс собщения SwiftMailer, что позволяет вам вызывать любые методы для создания своего сообщения.
Добавление встроенных вложений
Обычно добавление встроенных вложений в письмо обычно утомительное занятие, однако Laravel делает его проще, позволяя вам добавлять файлы и получать соответствующие CID.
Встроенные (inline) вложения - файлы, не видимые получателю в списке вложений, но используемые внутри HTML-тела сообщения; CID - уникальный идентификатор внутри данного сообщения, используемый вместо URL в таких атрибутах, как src - прим. пер.
Добавление картинки в шаблон сообщения
body> Вот какая-то картинка: img src="embed($pathToFile); ?>"> body>
Добавление встроенной в html картинки (data:image)
body> А вот картинка, полученная из строки с данными: img src="embedData($data, $name); ?>"> body>
Переменная $message всегда передаётся шаблонам сообщений классом Mail .
Очереди отправки
Из-за того, что отправка писем может сильно повлиять на время отклика приложения, многие разработчики помещают их в фоновую очередь на отправку. Laravel позволяет делать это, используя единое API очередей. Для помещения сообщения в очередь просто используйте метод Mail::queue() :
Помещение сообщения в очередь отправки
Mail::queue('emails.welcome', $data, function($message) < $message->to('foo@example.com', 'Джон Смит')->subject('Привет!'); >);
Вы можете задержать отправку сообщения на нужное число секунд методом later :
Mail::later(5, 'emails.welcome', $data, function($message) < $message->to('foo@example.com', 'Джон Смит')->subject('Привет!'); >);
Если же вы хотите поместить сообщение в определённую очередь отправки, то используйте методы queueOn и laterOn :
Mail::queueOn('queue-name', 'emails.welcome', $data, function($message) < $message->to('foo@example.com', 'Джон Смит')->subject('Привет!'); >);
Локальная разработка
При разработке приложения обычно предпочтительно отключить доставку отправляемых сообщений. Для этого вы можете либо вызывать метод Mail::pretend , либо установить параметр pretend в значение true в файле настроек config/mail.php . Когда это сделано, сообщения будут записываться в файл журнала вашего приложения, вместо того, чтобы быть отправленными получателю.
Если вы хотите отладить вид отсылаемых писем, воспользуйтесь сервисом типа MailTrap.
Русскоязычное комьюнити
- Группа в VK
- Телеграм LaravelRUS
- Телеграм Laravel для новичков
- Телеграм LaravelPro
Обучающие ресурсы
- Laracasts
- Codecourse
- Курс Дмитрия Елисеева
- Adam Wathan
Блоги разработчиков
- Laravel News
- Freek Van der Herten
- Brent Roose
- Marcel Pociot