The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Отправка писем с авторизацией на SMTP-сервере из Perl (smtp auth perl)


<< Предыдущая ИНДЕКС Исправить src / Печать Следующая >>
Ключевые слова: smtp, auth, perl,  (найти похожие документы)
From: Денис Назаров <marsden at mail.ru> Newsgroups: email Date: Mon, 30 Aug 2008 18:21:07 +0000 (UTC) Subject: Отправка писем с авторизацией на SMTP-сервере из Perl Введение Возникла задача - отправка письма без использования sendmail, без настройки своего smtp-сервера - то есть на минимальной десктопной системе. Осложнялась задача тем, что к письму необходимо было прицеплять вложения. Отсутсвие своего почтового сервера привело к решению использовать ящик на одном из бесплатных почтовых серверов, в частности - mail.ru. Готовых примеров в интернете нашлось немало, но почти у всех были недостатки - использование sendmail или других сторонних программ и самый главный - отсутствие авторизации на smtp сервере. Нашелся, впрочем, в котором довольно подробно описан процесс взаимодействия с сервером, в том числе авторизация. В результате получился небольшой скрипт на perl, который можно легко доработать под свои нужды. Результат #!/usr/bin/perl use MIME::Base64; #для кодирования авторизационных параметров, темы и тела письма use IO::Socket; #для общения с SMTP-сервером use Text::Iconv; #для перекодирования текста my $mailbox = 'xxxxxx@mail.ru'; # ящик-отправитель my $mailpwd = 'xXxYyYzZz'; # пароль my $mailrcpt = 'yyyyyyy@mail.ru'; # ящик-получатель my $subj = 'Привет, это я!'; my $mail = 'Отправляю тебе свою фотку с Черного моря :)'; my $attachment = 'foto.jpg'; # файл-вложение my $attachpath = '/home/user/Documents/'; # путь к нему # поскольку данный скрипт я пишу в кодировке UTF-8, # а письмо хочу отправлять в кодировке Windows, то мне просто необходим # перекодировщик для кодирования из UTF-8(юникод) в CP1251(Windows) my $cnv = Text::Iconv->new('UTF8','CP1251'); my $reply; # код ответа сервера my $message; # текст ответа сервера #открываем сокет к SMTP-серверу my $socket = IO::Socket::INET->new('smtp.mail.ru:25'); defined $socket or die "ERROR: $!\n"; # читаем ответ if(ReadReply() ne 220){print "Ошибка установки связи = $message\n"; $socket->close(); exit} # здороваемся с сервером - не стал использовать ehlo, # потому что расширенные возможности не требуются $socket->print ("helo lo\n"); # получаем ответ и проверяем код if(ReadReply() != 250){print "Ошибка приветствия сервера = $message\n"; $socket->close(); exit} # теперь проводим авторизацию $socket->print("AUTH LOGIN\n"); # получаем ответ if(ReadReply() ne 334){print "Ошибка авторизации = $message\n"; $socket->close(); exit} # кодируем логин-пароль $socket->print(encode_base64($mailbox).encode_base64($mailpwd)); # после авторизации выдается две строчки ReadReply(); if(ReadReply() ne 235){print "Ошибка авторизации = $message\n"; $socket->close(); exit} # начинаем транзакцию - даем команду отправки письма $socket->print('mail from: '."$mailbox\n"); if(ReadReply() ne 250){print "Ошибка в почтовом ящике отправителя = $message\n"; $socket->close(); exit} # указываем получателя $socket->print("rcpt to: $mailrcpt\n"); if(ReadReply() ne 250){print "Ошибка в почтовом ящике получателя = $message\n"; $socket->close(); exit} # теперь начинаем формировать письмо $socket->print("data\n"); if(ReadReply() ne 354){print "Ошибка при начале формирования письма = $message\n"; $socket->close(); exit} # теперь сформируем тему письма, перекодировав ее из юникода в ср-1251 # и потом закодировав все это в base64. # Таким образом, в теме письма можно нормально писать по русски # Если вы используете другую кодировку в системе и/или при подготовке # этого скрипта под свои нужды - скорректируйте создание конвертера в начале # или вообще откажитесь от него $subj = encode_base64($cnv->convert($subj)); $subj =~ s/\n//ig; # уберем символы перевода строки $subj =~ s/\r//ig; # и возврата каретки, поскольку они все ломают :) $subj = '=?Windows-1251?B?'.$subj.'?='; # создадим тело письма $msg = encode_base64($cnv->convert($mail)); # здесь формируем заголовок, минимальная версия $body = "Mime-Version: 1.0\n"; $body .= "Content-Type: multipart/mixed; boundary=\"-\"\n\n"; # вставляем тело письма $body .= "---\nContent-Type: text/plain;\n\tcharset=\"Windows-1251\"\nContent-Transfer-Encoding: base64\n\n$msg\n"; # и прицепляем файл-вложение $body .= "---\nContent-Type: application/octet-stream; name=\"$attachment\"\n"; $body .= "Content-Transfer-Encoding: base64\n"; $body .= "Content-Disposition: inline; filename=\"$attachment\"\n\n"; # чтобы сформировать вложение, открываем файл # в двоичном режиме, считываем его в память и кодируем в base64 $txt = ''; open f,"$attachpath$attachment"; binmode f; while($str=<f>){$txt.=$str}; close f; $body .= encode_base64($txt)."\n---\n"; # и наконец соберем письмо в одну переменную :) $mailmessage = "From:$mailbox\nTo:$mailrcpt\nSubject:$subj\n$body\n.\n"; # скинем письмо серверу $socket->print($mailmessage); # и посмотрим что получилось if(ReadReply() ne 250){print "Ошибка при отправке письма = $message\n"; $socket->close(); exit} # если дошли до этого места, значит письмо ушло $socket->close(); print "Письмо отправлено\n"; sub ReadReply{ # процедура чтения ответа от сервера # цикл используется для того, чтобы прочитать многострочный ответ # например, при выдаче ответа на команду EHLO # формат строк # Трехзначное число-пробел или дефис-текстовое сообщение # причем, если ответ многострочный, то дефис используется во всех # строках, кроме последней, в которой используется пробел # именно по этому признаку и будет определятся конец цикла # и возвращаемый код будет браться также из последней строки $val = 1; while($val eq 1){ $r = <$socket>; $val = $r =~ m/^\d{3}-/g; } ($reply,$message) = split(/ /,$r,2); return $reply; } Ссылки пример на php - http://webi.ru/webi_articles/6_10_f.html пример использования сокетов - http://www.opennet.dev/base/dev/perl_sendmail.txt.html Денис Назаров marsden at mail.ru август 2008

<< Предыдущая ИНДЕКС Исправить src / Печать Следующая >>

Обсуждение [ RSS ]
  • 1, guest (??), 16:40, 02/09/2008 [ответить]  
  • +/
    Большое спасибо. Очень толковое описание.
     
  • 2, zguest (??), 00:55, 25/02/2009 [ответить]  
  • +/
    Очень полезная статья, легко читаемо и переводимо на другие алгоритмы.
     
  • 3, Денис Назаров (?), 11:27, 01/03/2009 [ответить]  
  • +/
    ага, только в процессе использования выяснилось, что надо бы еще одну переменную ввести, например $mailuser и использовать ее при авторизации, потому что не на всех почтовых серверах в качестве логина применяется адрес ящика, потом кодирование темы и самого тела письма тоже можно вытащить вверх до авторизации, чтобы сам процесс отправки можно было затолкать в цикл. А так вполне жизнеспособная вещь получилась :) В общем-то сделалось все за пару дней, так что можно еще шлифовать
     

     Добавить комментарий
    Имя:
    E-Mail:
    Заголовок:
    Текст:




    Партнёры:
    PostgresPro
    Inferno Solutions
    Hosting by Hoster.ru
    Хостинг:

    Закладки на сайте
    Проследить за страницей
    Created 1996-2024 by Maxim Chirkov
    Добавить, Поддержать, Вебмастеру