Сегодня решил немного поэкспериментировать с библиотекой Synapse и научиться отправлять письма, используя протокол SMTP (Simple Mail Transfer Protocol — протокол передачи почты). Тема эта достаточно интересная и полезная. Дело даже не в том, чтобы написать для себя почтовый клиент, коих миллионы. Подобные навыки работы с бибилиотекой могут потребоваться, например, если Вы захотитенаписать своего клиента для отправки сообщений в свой блог на ЖЖ, Blogger или LiveInternet — эти блог сервисы поддерживают публикацию новых постов по e-mail. Так что, полученные сегодня навыки несомнено должы принести Вам (мне точно) определенную пользу. Для работы с протоколом SMTP в Synapse можно использовать следующие модули библиотеки:
- smtpsend — содержит объект Tsmtpsend и ключевые методы для отправки электронных писем.
- mimemess — содержит объекты TMessHeader — заголовки сообщения; TMimeMess — сообщение;
- mimepart — содержит объект TMimePart для работы с частями сообщения, которые можно использовать для отправки по почте файлов.
Сегодня сосредоточимся на основной задаче — отправке текста. Так как именно для этого в свое время и был создан SMTP, а пересылкой файлов (аттачей) занимается не протокол, а расширение к протоколу — MIME (Multupurpose Internet Mail Extentions, RFC-1521). Расширениями займемся позднее.
Итак, сегодня в наши задачи входит:
- Составить правильный заголовок сообщения
- Добавить в сообщение текст (plain text) или html-код
- Оправить сообщение на постовый ящик, используя заданый smtp-сервер.
1. Подготавливаемся к работе с SMTP в Delphi. Загоовка приложения.
Открываем Delphi, создаем новое приложение и на главной форме размещаем компоненты как показано на рисунке:
Как вы знаете, SMTP-серверы почтовых служб таких как mail.ru требуют обязательной авторизации, поэтому на форме нашего будущего приложения предусмотрены два поля: «Логин пользователя» и «Пароль пользователя» — туда будем записывать данные для авторизации на SMTP-сервере.
Поле «Хост» должно содержать хост smtp-сервера, например, smtp.mail.ru или smtp.yandex.ru и т.д., смотря от чьего имени вы будете слать письма. Поле «Адрес e-mail» для отправителя должен содержать правильный адрес, т.е. применительно к mal.ru, если ваш логин «blogger», то ящик должен быть «blogger@mail.ru», а хост «smtp.mail.ru».
С формой приложения и назначением элементов главной формы, думаю, разобрались. Переходим ко второму пункту нашей работы — создадим правильное сообщение.
2. Формируем сообщение e-mail, используя Synapse
Итак, в заголовки сообщения нам необходимо включить:
- Имя отправителя
- Адрес отправителя
- Список получателей (в нашем случае получатель будет один)
Подключаем к проекту модули mimemess, mimepart, smtpsend. Создаем процедуру с названием, например SendMail:
Procedure SendMail (Host, Subject, pTo, From , TextBody, HTMLBody, login,password : string); var Msg : TMimeMess; //собщение StringList : TStringList; //содержимое письма MIMEPart : TMimePart; //части сообщения (на будущее) begin Msg := TMimeMess.Create; //создаем новое сообщение StringList := TStringList.Create; try // Добавляем заголовки Msg.Header.Subject := Subject;//тема сообщения Msg.Header.From := From; //имя и адрес отправителя Msg.Header.ToList.Add(pTo); //имя и адрес получателя // создаем корневой элемент MIMEPart := Msg.AddPartMultipart('alternative', nil); if length(TextBody)>0 then begin StringList.Text := TextBody; Msg.AddPartText(StringList, MIMEPart); end else begin StringList.Text := HTMLBody; Msg.AddPartHTML(StringList, MIMEPart); end; // Кодируем и отправляем Msg.EncodeMessage; smtpsend.SendToRaw(From, pTo, Host, Msg.Lines, login, password); finally Msg.Free; StringList.Free; end; end;
Разберем по частям, что к чему. В начале создаем новое сообщение, используя объект TMimeMess (сообщение) из модуля Synapse mimemess.
Далее добавляем в сообщение все необходимые заголовки. Создаем объект TMimePart. Так как создается корневой элемент MIME, то вторым параметром, согласно условиям работы с Synapse, ставится nil. Если мы отправляем простой текст, то используем метод AddPartText, где вторым параметром выступает как раз созданные нами корневой элемент, иначе, если текстовое содержимое не отсылается, то принимаем, что отсылается HTML-код и используем соответственно метод AddPartHTML. Также Вы можете добавить в сообщение:
- Текст из файла, используя метод AddPartTextFromFile.
- HTML-код из файла, используя метод AddPartHTMLFromFile
- Бинарный файл, загрузив данные в поток TStream и указав его в параметрах метода AddPartBinary
Есть ещё ряд других методов, расширяющих возможности объекта TMimePart, разобраться с работой которых, думаю, будет достаточно просто.
После того, как сообщение собрано, мы его кодируем, используя метод EncodeMessage, в котором собираются правильные, согласно RFC заголовки, «склеиваются» все части и т.д. И, наконец, отправляется письмо, используя метод SendToRaw из модуля Synapse httpsend.
Теперь, когда основная процедура отправки готова. Дописываем приложение.
3. Дорабатываем приложение для отправки почты.
В обработчике onClick кнопки пишем:
procedure TForm5.Button1Click(Sender: TObject); begin if RadioButton1.Checked then SendMail(Edit1.Text, 'Test Message', '"' + Edit4.Text + '" <' + Edit5.Text + '>', '"' + Edit2.Text + '" <' + Edit3.Text + '>', Memo1.Text, '', Edit6.Text, Edit7.text) else SendMail(Edit1.Text, 'Test Message', '"' + Edit4.Text + '" <' + Edit5.Text + '>', '"' + Edit2.Text + '" <' + Edit3.Text + '>', '', Memo1.Text, Edit6.Text, Edit7.text) end;
Теперь можете проверить работу приложения. Например я отправил себе на второй ящик письмо:
И спустя буквально пару секунд получил новое письмо на свой ящик:
Теперь можете потренироваться с приложением, добавить возможность отправки файлов по электронной почте и т.д. Как видите, с Synapse не только просто работать с HTTP и HTTPS-протоколами, но и не менее просто отправлять электронную почту.
так что насчет отправки почты через прокси? возможно ли ?
«используя метод SendToRaw из модуля Synapse httpsend.»
это я так полагаю ошибка, в коде используется модуль smtpsend который может отправлять похоже только через сокс5 прокси? возможно ли через http прокси отправлять почту?
alex, я сам через прокси никогда с почтой не работал. Поэтому сказать можно или нет — не могу.
Дай исходник темы.
какой темы?
Пишу здесь, значит этой «Synapse. Отправка писем, используя SMTP.».
исходник не сохранился. Он весь в статье — 2 процедуры.
на некоторых компах под Windows 7 не работает отправка сообщения. Файервол и антивирус отключены и ошибок никаких не возникает ни на стадии компиляции, ни в процессе работы. Может быть какая-нибудь служба блокирует отправку?
Все работает и исходник изменил, всем огромное спасибо, вот только при приеме Батом в html вылазит бяка в начале текста стоит символ верхней точки… , даже если пустое письмо в html отправляешь…так и не разобрался как убрать (((
Ребята, не могу понять в чем дело.
Код целиком стащил, ничего не менял. Была ошибка с > прочел что это < , изменил. Все скомпилилось, запустилось. Но ничего не отправляется. Очень нужно решить эту проблему.
Здравствуйте. Очень рад, что наткнулся на эту статью. Скопировал себе полностью код, ничего не меняя. Компиляция прошла успешно, на письмо не доходит. Отправляю с mail.ru на mail.ru Не пойму, в чем дело. Может может кто помочь? Я могу выслать исходники. Очень нужно разрешить данный вопрос.
Благодарю за помощь
Здравствуйте. У меня вопрос по поводу запроса о получении (доставке). Отправляю письма на mail и yandex c заголовками :
// запрос о прочтении
X-Confirm-Reading-To: отправитель@мейл.ру
Disposition-Notification-To: отправитель@мейл.ру
// запрос о получении
Return-Receipt-To:отправитель@мейл.ру
mail реагирует ТОЛЬКО на запрос О ПРОЧТЕНИИ
yandex же вообще ни как не реагирует
в чем может быть проблема или есть другие способы получить отчет о получении?
Александр, вопрос как нельзя кстати :) Правда. Только сегодня утром узнал, что в ближайшее время мне предстоит сделать вот такие вот уведомления в программе…правда мы используем на работе Indy, но сути дела это не меняет. Думаю, что после того как разберусь с этой темой отпишу пост в блоге. Пока ответить на вопрос не могу ибо ещё не до конца в теме…
Vlad, спасибо за столь оперативный ответ) Если сам догадаюсь дам знать
Александр, не за что :) Буду очень признателен, если не забудете отписаться в случае успешного решения задачки.
Влад, привет. Объясни, пожалуйста, как добиться прихода ответной квитанции о доставке сообщения с помощью synapse? Писал в службу mail и yandex. Говорят, они такую информацию не предоставляют. Как-то это сделано в outlook, значит принципиально возможно. Перепробовал все что написано выше-не работает.
Vlad, решил я вопрос с доставкой :) пришлось прочитать пару иностранных источников по SMTP протоколу, потом тестировать через Telnet, и как всегда все самое сложно пишется в одну строчку :) Сразу скажу что получение отчета о доставке зависит от возможностей smtp сервера, а точнее его возможность поддерживать DSN (Delivery Status notification — уведомлений о состоянии доставки). Из известных это yandex ( даже не gmail :) ), ну или Ваш если поддерживает, как это узнать могу Вам написать куда-нибудь. А само решение такое: нужно подправить исходник synapse, а точнее smtpsend.pas в нем в функции function TSMTPSend.MailTo(const Value: string): Boolean; строку FSock.SendString(‘RCPT… Подробнее »
Александр, спасибо огромное :) Уже который день читаю всякие RFC про DSN, но открытым остается вопрос — как однозначно определять поддерживает сервер DSN или нет? И, если не поддерживает, то как-то говорить пользователю об этом, чтобы потом не было баг-репортов типа «А я задал прислать мне отчёт о доставке, а он не доставил! :(» и всё такое :)
Vlad, можно так: ( пример для yandex )
1.Открываем командную строку ( Выполнить => cmd )
2.набираем «telnet smtp.yandex.ru 25″ ( все дальше без кавычек ) ждем ответа от сервера
3.»EHLO ip» (ваш ip — это у яндекса, у меня на работе например логин от мыла, тот что до @, на mail.ru вообще любая строка подходит, т.е. в зависимости от сервера)
4.Сервер выдает нам список поддерживаемых команд, и если там есть DSN — значит поддерживает.
Александр, понятно. Спасибо ещё раз. Как говориться, «будем посмотреть» :) Думаю, что всё получиться норм.
Как отправить нескольким получателям используя smtp.MailData?
Спасибо
Все замечательно отправляется и работает, НО! Работаешь в слепую: не выводится ни одной ошибки, мало того, нет возможности их вывести. Все что ты можешь это узнать отвправлена почта или нет. А Почему — нет ответа. Хотя в Smtpsend.pas есть интересный код: function TSMTPSend.EnhCodeString: string; var s, t: string; begin s := IntToStr(FEnhCode2) + '.' + IntToStr(FEnhCode3); t := ''; if s = '0.0' then t := 'Other undefined Status'; if s = '1.0' then t := 'Other address status'; if s = '1.1' then t := 'Bad destination mailbox address'; if s = '1.2' then t := 'Bad destination system… Подробнее »
Пытаюь отправить письма при помощи synapse с уведомлением и ни фига… Выше написано:
»
А само решение такое: нужно подправить исходник synapse, а точнее smtpsend.pas в нем в функции function TSMTPSend.MailTo(const Value: string): Boolean; строку
FSock.SendString(‘RCPT TO:’ + CRLF); заменить на :
FSock.SendString(‘RCPT TO:’ + ‘ NOTIFY=SUCCESS’ + CRLF);
»
но в функции TSMTPSend.MailTo нет такой строки… там есть
FSock.SendString(‘RCPT TO:’ + CRLF);
и если ее поменять по аналогии, то функция отправки фозвращает false и письма вообще не отправляются… Не подскажите куда покопать?
sergej, копать в сторону сервера. Он DSN вообще поддерживает? Если нет, то и NOTIFY нельзя использовать
Спасибо за ответ. Только не очень понял… Или я плохо пояснил. После правки функция
smtpsend.SendToRaw(pFrom, pTo, pHost, tmpMsg.Lines, plogin, ppassword) возвращает false и письмо не отправляется. Как только правку убираю — все ок, письмо приходит. Слал письмо на mail.ru, а он вроде все поддерживает. Да и опять же, даже если DSN не пддерживается, то письмо-то доходить до адресата вроде должно…
sergej, mail.ru не поддерживает DSN. Пробуйте yandex
Вы пишите: «но в функции TSMTPSend.MailTo нет такой строки… там есть
FSock.SendString(‘RCPT TO:’ + CRLF);» наверное FSock.SendString(‘RCPT TO:’ + CRLF); ??? ее и нужно заменить на
FSock.SendString(‘RCPT TO:’ + ‘ NOTIFY=SUCCESS’ + CRLF);
сори вот это верно
Вы пишите: «но в функции TSMTPSend.MailTo нет такой строки… там есть
FSock.SendString(‘RCPT TO:’ + CRLF);» наверное FSock.SendString(‘RCPT TO’ + CRLF); ??? ее и нужно заменить на
FSock.SendString(‘RCPT TO:’ + ‘ NOTIFY=SUCCESS’ + CRLF);;
не знаю что с моим компьютером….сори за кучу сообщений
RCPT TO:’ + ‘ NOTIFY=SUCCESS’ + CRLF // Value не забыть между RCPT TO: и NOTIFY=SUCCESS
Александр, спасибо за ответ. Прошу прощения я неверно привел пример строки. В общем вот эта функция целиком
function TSMTPSend.MailTo(const Value: string): Boolean;
begin
FSock.SendString('RCPT TO:' + CRLF);
Result := ReadResult = 250;
end;
я пробовал менять вот так
FSock.SendString('RCPT TO: NOTIFY=SUCCESS'+CRLF);
про яндекс.ру спасибо — попробую.
сорри, не так скопировал…
менял вот так
FSock.SendString('RCPT TO: NOTIFY=SUCCESS'+CRLF);
ууууууууу,как тут все запущено однако… я думал, что это я ошибаюсь, а оказывается тутошний движок мягко говоря мудрит… выбрасывает куски текста… че за бред…
куда девается контекст «+ value +»
пробую еще раз привесты примеры….
function TSMTPSend.MailTo(const Value: string): Boolean;
begin
FSock.SendString(‘RCPT TO:’ + CRLF);
// FSock.SendString(‘RCPT TO: NOTIFY=SUCCESS’+CRLF);
Result := ReadResult = 250;
end;
да это полный бред… ваш движок творит «чудеса» Вставляешь одно, а он вставляет другое…
Работающий пример DSN Яндекс.Почты. Видео-ролик, подтверждающий работу приведенного кода приведен.
Огромное спасибо за проделанную работу! Теперь надо только все это понять и освоить (усвоить).
Всегда пожалуйста :) Чтобы освоить все, что я тут написал очень рекомендую ознакомиться со всеми приведенными в статье RFC, хотя бы в переводе. Реально очень помогают
Можно получить исход? уже 3,5 часа вожусь c smtp а письмо так и не смог отправить(
вот не найду я сейчас этот исходник уже…можно глянуть на GitHub — там есть компонентик для GMail — он тоже использует TSMTPSend
Подскажите в ХЕ5 перестал отправлять письма. Изначально ругался TimeSeparator заменил на FormatSettings.TimeSeparator
так же ругался на
CustomMonthNames[n] := ShortMonthNames[n];
MyMonthNames[0, n] := ShortMonthNames[n];
изменил на
FormatSettings.ShortMonthNames[n]
FormatSettings.ShortMonthNames[n]
но письма не отправляются
Относительно предыдущего вопроса
Релиз Release 40 2012-04-23 отправка почты не работает
а вот старый который использую
Release 39 2009-10-08 все гуд работает и на xe5
А как сделать так чтобы отправлялась без libeay32.dll,ssleay32.dll, может какой-нить модуль к проекту надо подключить, или скомпилировать сразу проект с этими длл??
Может быть и есть такой способ, но я о нем не знаю. Да и нет ничего сложного положить 2 dll рядом с exe
[…] прошлой статье про использование Synapse для отправки писем мы разработали простенькое приложение для отправки […]
[…] Если либа Synaps’а у тебя ещё не установлена, по каким-то причинам, или же ты не знаешь как ей пользоваться — то рекомендую следующие мануалы и ресурсы: скачать Synapse, установка Synapse, установка в картинких и мануал по адаптации к новым версиям Delphi (XE+), отправка smtp-писем, используя Synapse. […]
здраствуйте,использую делфи 2010,полностью скопировал ваш код,но выдает ошибку [DCC Error] Unit1.pas(50): E2012 Type of expression must be BOOLEAN ,в строке if length(TextBody)>0 then
Привет всем!!!
Наберусь смелости задать вопрос!
Заголовки письма
TMimeMess
From: «=?ISO-8859-5?Q?=C0=DE=D1=…
To: «=?ISO-8859-5?Q?=…
Subject: =?ISO-8859-5?Q?=BB=DE=D3_…
Для кодировки символов работает
Msg.Header.CharsetCode:=CP1251 или UTF_8
IdealCharsets:=[UTF_8];
Как в !!!!!!!!!!!заголовке!!!!!!!!!!!!! указать свои ME_7BIT, ME_8BIT, ME_QUOTED_PRINTABLE and ME_BASE64
вместо ME_QUOTED_PRINTABLE
Напимер:
AddPartTextEx(StringList, MIMEPart, CP1251, True, ME_BASE64);
Это работает но для текста письма.
Спасибо!!!