Как отправить e-mail?

Автор: Виталий Брусенцев
The RSDN Group
Опубликовано: 03.10.2001
Версия текста: 0.9


Способ 1 (самый простой) - гиперссылка "mailto:"
Способ 2 (Simple MAPI) - MAPISendDocuments
Способ 3 (Simple MAPI) - MAPISendMail
Способ 4 (более современный) - Collaboration Data Objects
Способ 5 (CDONTS NewMail)
Способ 6 (CDO для Windows 2000)
Способ последний (для мазохистов)


Демонстрационный проект (Simple MAPI, CMC) - 26 Кб

Этот вопрос возникает в ньюсгруппах с завидной постоянностью. Для отправки электронного письма существует несколько способов, доступных (или недоступных) в зависимости от настройки пользовательского компьютера. Не все они равноценны. Во всех примерах отсутствует проверка ошибок, так что не обольщайтесь - все еще сложнее, чем вы думаете :)

Способ 1 (самый простой) - гиперссылка "mailto:"

Доступен даже из bat-файлов (через команду start). На компьютере должен быть установлен и настроен почтовый клиент. Если необходимо отправить письмо по адресам email1 и email2 , копию - по адресу email3 с темой "Subject text" и текстом "Body\nText", то достаточно сформировать гиперссылку:

mailto:email1;email2&cc=email3?subject=Subject%20text&body=Body%0dText

Ее можно поместить на веб-страницу (в теге <A href=...>). Щелчок мышью на такой ссылке приведет к открытию окна почтового клиента с готовыми параметрами письма. Пользователю останется только нажать кнопку "отправить". Открыть такую гиперссылку можно и программно (например, с помощью функции ShellExecute).

Вложенные файлы таким способом отправить не удастся.

Способ 2 (Simple MAPI) - MAPISendDocuments

Доступен из WinAPI-приложений, в том числе из Visual Basic (для него существует специальная обертка этой библиотеки в файле MAPIVB32.BAS)

Ваша программа может использовать различные сервисы MAPI. Здесь я описываю Simple MAPI. В демонстрационном проекте можно найти пример использования CMC. Все описываемые функции недоступны через библиотеки импорта (вследствие очень гибкой архитектуры MAPI). Для их использования необходимо явно загрузить библиотеку mapi32.dll и получить адрес необходимой функции с помощью GetProcAddress.

Для этого способа необходим почтовый клиент, поддерживающий MAPI - например, Netscape Messenger, Outlook Express, Exchange client, Microsoft Outlook 2000 (см. примечание).

Simple MAPI предоставляет несколько способов отправить письмо. Самый простой в реализации - функция MAPISendDocuments. В отличие от предыдущего способа, здесь нет проблем с вложениями, но нельзя ввести текст письма:

typedef ULONG (FAR PASCAL *SendProc)( ULONG ulUIParam,        
                  LPTSTR lpszDelimChar, LPTSTR lpszFullPaths, 
                  LPTSTR lpszFileNames, ULONG ulReserved);
HMODULE h = LoadLibrary("Mapi32.dll");
SendProc fnSend = (SendProc)GetProcAddress(h,MAPISendDocuments);
fnSend((ULONG)hwndMain, ";", "C:\\MyDoc.DOC;C:\\Doc2.DOC", "My Document.DOC;Doc2.DOC", 0); 
FreeLibrary(h);

ulUIParam - может содержать HWND окна, дочерним к которому будет диалог "Написать письмо". lpszDelimChar - разделитель имен вложенных файлов (в данном случае - ";"). Параметры lpszFullPaths и lpszFileNames соответственно описывают пути к существующим файлам (для вложения) и их названия в письме.

Кроме невозможности написать текст, имеется еще один существенный недостаток - на экране появится диалог почтового клиента "Отправка сообщения", в котором пользователь должен будет выбрать подтверждение.

ПРИМЕЧАНИЕ

Microsoft Outlook 2000 настраивается по умолчанию в режиме Internet-only. При этом MAPI не поддерживается. Для того, чтобы включить MAPI, необходимо перевести Outlook 2000 в корпоративный режим и затем уже настроить учетные записи

Способ 3 (Simple MAPI) - MAPISendMail

Также предназначен для WinAPI-программ.

Наиболее функциональный способ, но по-прежнему требует наличия MAPI-совместимого клиента. Справедливо все, что говорилось про Simple MAPI. Ваша программа имеет выбор - скрыть интерфейс почтового клиента или нет, предоставить пользователю возможность авторизации или произвести ее самостоятельно, отправлять ли набор вложений и выбирать ли адресатов из адресной книги.

Из за громоздкости примера он приведен полностью в демонстрационном проекте (функция CMailerMAPI::send). Здесь скажу только, что зачастую вместе с MAPISendMail используется "сладкая парочка" MAPILogon/MAPILogoff (для программной авторизации пользователя).

Способ 4 (более современный) - Collaboration Data Objects

Не все почтовые клиенты поддерживают модель CDO. Она есть, например, в Microsoft Outlook 2000 (но не устанавливается по умолчанию). Для ее установки необходимо выбрать опцию "Объекты совместной работы".

Модель объектов довольно удобная и понятная. Приведу пример на JScript:

var cdoFileData=1;
var session=new ActiveXObject("MAPI.Session");
session.Logon("user", "password");
var msg=session.Outbox.Messages.Add("Subject text", "Body text!");
var recip=msg.Recipients.Add();
recip.Name="someone@microsoft.com";
recip.Type=1;
recip.Resolve(true);
msg.Attachments.Add("MyFile.Doc", 0, cdoFileData, "C:\\Documents\\MyDoc.doc");
msg.Send();
session.Logoff();

Отмечу, что появляется возможность послать не сам файл, а ссылку (cdoFileLink=2) на него. Это имеет смысл, если у вас есть общий с адресатом файловый сервер. В этом случае система не проверяет достоверность имени файла.

Способ 5 (CDONTS NewMail)

Хорошо подходит для ASP-приложений и сервисов NT/2000, которым надо посылать много коротких почтовых сообщений. Этот сервис устанавливается с некоторыми серверными продуктами Microsoft, например, IIS 4.0 и выше. Для нормального функционирования CDONTS необходимо настроить SMTP Service в IIS. Начиная с версии CDONTS 1.2, поддерживаются почтовые вложения. Пример на VBScript:

Set objNewMail = CreateObject("CDONTS.NewMail") 
objNewMail.AttachFile "\\server\Documents\MyDoc.doc", "MyFile.Doc" 
objNewMail.Send "Generator", "someone@microsoft.com", "Subject", "The message body", 0 
Set objNewMail = Nothing

Заметьте, что не требуется (да и не поддерживается) авторизация.

Способ 6 (CDO для Windows 2000)

Ярослав Говорунов и Алексей Остапенко:

CDO for W2K лучше, чем CDONTS и с кодировками проблем нет. Идет с IIS5. JScript:

var Msg = CreateObject("CDO.Message");
Msg.BodyPart.Charset="windows-1251";
Msg.From='"Отправитель" <sender@rsdn.ru>';
Msg.MimeFormatted=true;
Msg.Subject="Тема";
Msg.To = '"Получатель" <someone@rsdn.ru>';
Msg.BCC="one@rsdn.ru; two@rsdn.ru";
Msg.TextBody="Текст сообщения";
Msg.TextBodyPart.Charset="windows-1251";
Msg.Send();

Опять-таки необходимо настроить SMTP Service. CDO.Message также поддерживает вложения (метод AddAttachment).

Способ последний (для мазохистов)

Если компьютер подключен к Интернету, но на нем нет (и не будет) никакого почтового ПО, то в этом (и только в этом!) случае можно реализовать необходимую функциональность самому. Для этого необходимо реализовать общение по протоколу SMTP (Simple Mail Transfer Protocol, RFC 0821).

Что это означает? Этот протокол содержит набор текстовых команд, которыми могут обмениваться клиент и сервер для отправки почты. Так как требуется только отправить письмо, нам понадобится знать только 5 команд: HELO, MAIL, RCPT, DATA и QUIT. Предварительно необходимо соединиться с smtp - сервером (например, smtp.mail.ru) по 25 порту - стандартному порту для SMTP. Это позволяет сделать любое средство программирования, разрешающее использование сокетов. Далее наша программа (то есть клиент) посылает серверу набор команд для подключения, составления письма и его отправки. Ниже приведен типовой сеанс соединения с помощью telnet с воображаемым сервером smtp.myserver.com (жирным шрифтом показан ответ сервера):

>telnet smtp.myserver.com 25
HELO myserver.com
250 root.myserver.com myserver.com
MAIL FROM:<someone@myserver.com>
250 OK.
RCPT TO:<someone@microsoft.com>
250 OK.
DATA
354 Start mail input, end with <CRLF>.<CRLF>.
Blah blah blah
.
250 OK.
QUIT
Goodbye someone@myserver.com 

Здесь someone@myserver.com - адрес отправителя, someone@microsoft.com - адрес получателя. В конце письма необходимо поставить точку, о чем сервер нас честно предупреждает. Вообще говоря, надо внимательно анализировать ответы сервера и реагировать соответственно (например, может потребоваться ввести пароль). Так как задача довольно нудная и объемная, советую сначала взглянуть на готовую реализацию SMTP - мэйлера (например, на CodeGuru: http://www.codeguru.com/internet/smtp.shtml) и уже потом решать, стоит ли с этим связываться.

И в заключение добавлю, что вложения при этом способе также можно реализовать. Вкладываемый файл кодируется по определенному стандарту (чаще всего - MIME base64), после чего передается обычным текстом в теле письма. По этому поводу смотрите, например, http://www.codeguru.com/internet/mimemfc.shtml. Но можно использовать и более доступный стандарт кодирования, например распространенный у фидошников Uuencode.

Добавление от Тимофея Чадова:

Для парсинга mime есть замечательная вещь MIME++ (http://www.hunnysoft.com/mimepp/). Многоплатформенная. Отдается с документацией, исходниками и примерами для smtp, pop3, nntp. В общем-то сейчас ей и пользуюсь.


Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.