Perl для системного администрирования

         

Отправка почты


Начнем с рассмотрения механизмов отправки почты, а затем перейдем к более сложным вопросам. Традиционный (для Unix) Perl-код для

отправки почты бывает похож на пример, включенный в список часто задаваемых вопросов:

#

считаем, что ser.dmail установлен

open(SENDMAIL. "|/usr/lib/sendmail -oi -t -oaq") or

die "Невозможно запустить процесс для sendTiaii:

$!\n"; print SENDMAIL «"EOF"; From: от кого <me\$host> To:

кому <you\@othernost> Subject: Тема сообщения

Тело сообщения следует после пустой строки и может состоять из любого

количества строк.

EOF

close(SENDMAIL) or warn "Невозможно закрыть sendmail ";

Когда в Perl 5 изменились правила интерполяции массивов (по сравнению с Perl 4), очень много сценариев, отправляющих почту, перестали работать. Даже сейчас будьте осторожны и следите за таким кодом:

Saddress = "fred@example.com";

Чтобы все работало верно, его надо заменить на одну из следующих строк:

$address="fred\@example.com";

$address='fred@example.com1;



$address= join('@', 'fred', 'example.com');

Код, вызывающий sendmail, как было в нашем примере, во многих случаях будет работать отлично, но если в операционной системе не установлен агент передачи почты с именем «sendmail» (например, в NT или MacOS), он не будет работать никогда. В таких операционных системах выбор действий невелик.

Получение sendmail (или иного агента передачи почты)

Если вы работаете на Win32, то вам повезло, т. к. я знаю по крайней мере о трех версиях sendmail, перенесенных под Win32:

  • трех версиях sendmail, перенесенных под Win32:
  • Перенесенная версия sendmail от Cygwin (http://dome/weeg.ui-owa.edu/pub/domestic/sos/ports)
  • Коммерческая версия sendmail от Mercury Systems (http://www.de-mobuilder.com/sendmail.htm)
  • Коммерческая версия Sendmail for NT от Sendmail, Inc. (http:

    www.sendmail.com)

    Тем, кому нужно что-то менее тяжеловесное и кто хочет внести некоторые изменения в программу на Perl, чтобы поддержать различные аргументы командной строки, возможно, помогут достичь цели другие программы для Win32:




  • blat (http://www.interlog.com/~tcharron/blat.html)


  • netmall95 (http://www.geocitles.com/SlliconValley/Lakes/2382/net mail.html)


  • wmailto (http://www.impaqcomp.com/jgaa/wmailto.html)


  • Преимущества такого подхода состоят в том, что можно выбросить из сценария все сложности отправки почты. Хороший агент передачи почты (МТА) пытается повторно соединиться с почтовым сервером, если тот в данный момент недоступен, выбирает нужный целевой сервер (ищет записи Mail eXchanger в DNS и осуществляет переходы между ними), при необходимости переписывает заголовки, справляется с внезапными коллизиями и т. д. Если можно избежать необходимости заботиться обо всем этом в Perl, то это просто замечательно.



    Использование IPC, специфичных для операционной системы



    В MacOS или Windows NT можно управлять почтовым клиентом, используя IPC (Interprocess Communication, межпроцессные взаимодействия).

    Я не знаю о существовании версий sendmail для MacOS, но в нем для управления почтовым клиентом можно применять AppleScript:

    $to="someone\@example.com"; $from="me\@example.com"; $subject="Hi there"; $body="message body\n";

    MacPerl: :DoAppleScnpt(«EOC); tell application "Eudora"

    make message at end of mailbox "out"

    -- 0 is the current message

    set field \"from\" of message 0 to \"$frorn\"

    set field \"to\" of message 0 to \"$to\"

    set field \"subject\" of message 0 to \"$subject\"

    set body of message 0 to \"$body\"

    queue message 0

    connect with sending without checking

    quit

    end tell EOC В этом примере запускается очень простая программа AppleScript, которая общается с почтовым клиентом Eudora. Сценарий создает новое сообщение, помещает его в очередь для отправки, а затем отдает инструкции почтовому клиенту об отправке сообщения из очереди перед выходом.

    Еще один, более эффективный способ написать подобный сценарий состоит в том, чтобы использовать модуль Мае: : G1 ие, уже рассмотренный в главе 2 «Файловые системы».



    use Mac::Glue ':glue ;

    $e=new Mac::Glue 'Eudora';

    $to="someone\@example.com"; $f rom="me\(<}>exainple. com";

    $subject="Hi there"; $body="<riessage body";

    $e->make(

    new => 'message',

    at => location(end => $e->obj(mailbox => 'Out')) );

    $e->set($e->obj(field => from => message => 0), to =4 $froin):

    $e->set($e->obj(field => to => message => 0), to => $to);

    $e->set($e->ob](field => subject => message => 0), to => Ssubject);

    $e->set($e->prop(body => message => 0), to => $body);

    $e->queue($e->obj(message => 0)); $е->соппесц sending => 1, checking => 0);

    $e->quit;

    В NT можно обратиться к библиотеке Collaborative Data Objects Library (раньше она называлась Active Messaging), простой в использовании надстройке на архитектуре MAPI (интерфейс прикладного программирования систем передачи сообщений). Вызвать эту библиотеку для управления таким почтовым клиентом, как Outlook можно, применив модуль Win32: :OLE следующим образом:

    $to="me\(Sexample.com"; $subject="Hi there";

    $body="message body\n";

    use Win32::OLE;

    # инициализируем OLE и COINIT_OLEINITIALIZE,

    необходимые при и использовании объектов MAPI.Session

    Win32: :OLE->Initialize(Win32: :OLE: :COINIT__OLEINITIALI7E): die Win32: :OLE->LastEr'-or(), "\n"

    if Win32: :OLE->LastErrc-( V

     создаем объект сессии, который вызовет logoff при уничтожени

    my Ssession = Win32::OLE->new('MAPI.Session','Logoff);

    die Win32::OLE->LastError();"\n" if Win32::OLE->LastError();

    № регистрируемся в этой сессии, используя OL98 Internet Profile по

    $session->Logon('Microsoft Outlook Internet Settings').

    die Win32: :OLE->LastError(),"\n" if Win32::OLE->LastError();

     создаем обьект message

    my Smessage = $session->Outbox->Messages->Add:

    die Win32:'OLE->LastError(),"\n" if Win32::OLE->LastError():



    Я создаем обьект recipient

    my Srecipient = $message->Recipients->Add;

    die Win32::OLE->LastError(),"\n" if Win32::OLE->LastError();

     заполняем данными объект recipient

    $recipient->{Name} = $to;

    $recipient->{Type} = 1; n 1 = "To:", 2 = "Cc:", 3 = "Вес:"

      все адреса должны быть расшифрованы по справочнику

    # (в этом случае, скорее всего, по вашей адресной книге)

     Полные адреса расшифровываются сами в себя, так что эта

     строка в большинстве случаев не изменит обьект recipient

    $ recipient->Resolve();

    die Win32: :OLE->LastError(). "\r> if Win32: :OLE->LastError();

    tt заполняем строку Subject: и тело сообщения

    $message->{Subject} = Ssubject; $message->{Text} = Sbody;

    tt помещаем сообщение в очередь для отправки

     1-й аргумент = сохранить копию сообщения

     2-й аргумент = позволить пользователю изменить сообщение

    tt перед отправкой в диалоговом окне

    № 3-й аргумент = родительское окно диалога, если 2-й аргумент True

    $message->Send(0, О, О):

    die Win32::OLE->LastError(),"\n" if Win32::OLE->LastError();

    tt явно уничтожить объект Ssession, вызвав

    $session->Logoff undef Ssession,

    В отличие от предыдущего примера, программа всего лишь помещает письмо в очередь. Это уже дело почтового клиента (такого как Outlook) или транспортного агента (например Exchange) периодически инициировать отправку почты. Существует CDO/AM 1.1 - метод для объекта Session под названием DeiiverNow(), обращающийся к MAPI с заданием очистить все очереди входящих и исходящих сообщений. К сожалению, в некоторых ситуациях он недоступен или не работает, поэтому его нет и в предыдущем примере.

    В упомянутом примере управление MAPI производится «вручную» при помощи вызовов OLE. Если вы хотите использовать MAPI, «не пачкая рук», можно применить модуль Win32: :МАР1, который берет на себя все функции (модуль находится на http://www.generation.net/ -aminer/Perl/ ).

    Программы, полагающиеся на AppleScript/Apple Events или MAPI, так же непереносимы, как и вызов программы sendmall. Они берут на себя часть работы, но относительно неэффективны. К этим методам нужно прибегать в последнюю очередь.





    Общение напрямую по почтовым протоколам



    Последний выбор - написать программу, общающуюся с почтовым сервером на его родном языке. Большая часть этого языка документирована в RFC821. Вот как выглядит основной обмен данными по SMTP (Simple Mail Transfer Protocol, простой протокол передачи почты). Данные, которые мы посылаем, выделены жирным шрифтом:

    %

    telnet example.com 25 -соединяемся с SMTP-портом на

    example.com

    Trying 192.168.1.10 ... Connected to example.com. Escape character is '"]'.

    220 mailhub.example.com ESMTP Sendmail 8.9.1a/8.9.1: Sun, 11 Apr 1999 15:32:16 -0400 (EOT)

    HELD client.example.com -идентифицируеммашину,с которой мы.

    пришли (можно использовать EHLO)

    250 mailhub.example.com Hello dnb@client.example.com [192.168.1.11]. pienSt;' to meet you

    MAIL FROM: «jnb@example.com> - определяем отправителя 250 <dnb@exarnple. com>... Sender ok

    RCPT TO: <dnb@example.com> - определяем получателя

    250 <dnb@example.com>... Recipient ok

    DATA - начинаем отправлять данные, не забывая о некоторых ключевых заголовках

    354 Enter mail, end with "." on a line by itself From:

    David N. Blank-Edelman (David N. Blank-Edelman) To: dnbeexample.com Subject: SMTP - хороший протокол

    Просто хочу напомнить себе о том, насколько я люблю SMTP. С миром, dNb

    - завершаем сообщение

    250 РАА266Р4 Message accepted for delivery QUIT - конец сессии

    221 mailhuD.example.com closing connection Cor.rectici closed by foreign host.

    Несложно записать в сценарий подобную беседу. Можно было бы использовать модуль Socket или что-нибудь вроде Net: : Telnet, как в главе 6 «Службы каталогов». Но существует несколько хороших модулей для отправки почты, которые упрощают эту задачу. Среди них модуль Женды Крыницки (Jenda Krynicky) Mail; :Se'-oer, Mai 1: :Sendmail Мили-вожа Ивковича (Milivoj Ivkovic) и Mail::Ma:Ier из пакета MailTools Грэхема Бара (Graham Barr). Все эти модули не зависят от операционной системы и будут работать практически везде, где доступен современный дистрибутив Perl. Мы рассмотрим Mail: :Mailer, поскольку он предлагает единый интерфейс к двум способам отправки почты, которые обсуждались до сих пор. Как и в случае с большинством модулей, написанных в объектно-ориентированном стиле, первый шаг заключается в создании экземпляра нового объекта:



    use Mail::Mailer;

    $f rom="me\@example. coin"; $to="you\@example.com";

    $subject="Hi there"; $body="message body\n";

    $type="srnto"; $server="mail.example,com";

    my Smaller = Mail::Mailer->new($type, Server -> $server) or die

    "Невозможно создать новый объект mailer:$'\n".

    Переменная $ type позволяет выбрать один из следующих типов поведения:

    smtp

    Посылает почту, обращаясь к модулю Net: :SMTP (часть пакета lib-net),

    доступному и для большинства не-Unix версий Perl. Если используется MailTools версии 1.13 или выше, можно задать имя SMTP-сервера, применяя приведенную выше символику =>. В противном случае, придется устанавливать имя сервера во время процедуры установки libnet.

    mail

    Отправка почты при помощи почтового агента mail (или любого другого, который задан вторым необязательным аргументом). Это напоминает недавнее использование AppleScript и MAPI.

    sendmail

    Отправка почты с помощью программы sendmail, как и в первом случае из данного раздела.

    Кроме того, можно установить переменную окружения PtRL_MAILERS, чтобы изменить путь, установленный по умолчанию для поиска программ (например,

    sendmail) в системе.

    Вызов метода ореп() для нашего объекта Mail:: Mailer заставляет последний выполнять роль дескриптора для исходящего сообщения. В этом вызове передаются заголовки сообщения ссылке на анонимный хэш:

    $mailer->open({From => $from, То => $to.

    Subject => Ssubject}) or die "Невозможно заполнить объект mailer

    Тело сообщения выводится в этот псевдодескриптор, который потом закрывается для отправки сообщения:

    print Smailer $body: $mailer->close;

    Этого вполне достаточно, чтобы отправка почты из Perl не зависела от системы.

    В зависимости от того, какой тип поведения $type был выбран при работе с модулем, могут оказаться скрытыми (а могут и не оказаться) более сложные вопросы, относящиеся к МТА, о которых уже говорилось. В предыдущем примере использовалось поведение smtp, а это означает, что программа должна быть достаточно умна, чтобы обрабатывать такие сбои как недоступность сервера. Приведенный пример не настолько «сообразителен». Обязательно позаботьтесь о таких моментах, когда будете писать программы.






    Содержание раздела