Отправка 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.

[править] Ссылки

[править] Лицензия на текст

Текст доступен на условиях лицензии Creative Commons Attribution/Share-Alike Cc-by-sa.png

[править] Материалы по настройке почтовых систем на Xgu.ru