Отправка e-mail из скриптов
Материал из Xgu.ru
На данной странице рассматриваются различные способы правильной отправки почтовых сообщений, содержащих не-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', 'Тестовый Отправитель <user@test.ru>'));
my $Mail_to = encode('MIME-Header', decode('utf8', 'Тестовый Получатель <user@test.ru>'));
Следует отметить использование функции 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 <from@email.ru>"' -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