В прошлой статье про использование Synapse для отправки писем мы разработали простенькое приложение для отправки текстового сообщения на e-mail. Сегодня доработаем процедуру отправки письма, а именно, сделаем возможность отпраки на e-mail любых файлов (вложений).
Вкратце напомню содержание предыдущей статьи по Synapse и SMTP. Для работы с электронной почтой мы использовали следующие модули библиотеки: smtpsend, mimemess и mimepart.
Отправка писем происходила по следующей схеме:
- Создавался объект TMimeMess для которого в заголовках указывались тема письма, адрес отправителя и адреса получателей
- Далее для объекта TMimeMess создавался корневой элемент сообщения, имеющий тип TMimePart
- В TMimePart добавлялся либо текст, либо HTML-код
- Последовательно вызывались два метода: метод объекта TMimeMess для кодирования письма - EncodeMessage и метод SendToRaw для отправки сообщения.
Сегодня немного расширим функциональность нашего приложения и отправим на почту вместе с текстом любой файл.
Для добавления в тело сообщения файлов в Synapse предусмотрены следующие методы объекта TMimeMess:
function AddPartBinary(const Stream: TStream; const FileName: string; const PartParent: TMimePart): TMimepart;
добавляет в содержимое сообщения бинарные данные из потока. При этом MIME-тип для вложения определяется автоматически по расширению файла (FileName), а все данные беруться из потока Stream.
function AddPartBinaryFromFile(const FileName: string; const PartParent: TMimePart): TMimepart;
Также добавляет вложение как и AddPartBinary, но, в отличие от предыдущего метода не требует указания потока с данными. MIME-тип определяется автоматически.
Воспользуемся вторым методом, т.е. AddPartBinaryFromFile и отправим на почту, например, изображение. Процедуру для отправки письма возьмем из предыдущей статьи, но немного её дополним:
Procedure SendMail (pHost, pSubject, pTo, pFrom , pTextBody, pHTMLBody : string); var tmpMsg : TMimeMess; tmpStringList : TStringList; tmpMIMEPart : TMimePart; begin tmpMsg := TMimeMess.Create; tmpStringList := TStringList.Create; try // Headers tmpMsg.Header.Subject := pSubject; tmpMsg.Header.From := pFrom; tmpMsg.Header.ToList.Add(pTo); // MIMe Parts tmpMIMEPart := tmpMsg.AddPartMultipart('alternate',nil); if length(pTextBody)>0 then begin tmpStringList.Text := pTextBody; tmpMsg.AddPartText(tmpStringList, tmpMIMEPart); end else begin tmpStringList.Text := pHTMLBody; tmpMsg.AddPartHTML(tmpStringList, tmpMIMEPart); end; if Form1.Edit1.Text<>'' then tmpMsg.AddPartBinaryFromFile(Form1.Edit1.Text,tmpMIMEPart) // кодируем и отправляем tmpMsg.EncodeMessage; smtpsend.SendToRaw(pFrom, pTo, pHost, tmpMsg.Lines, 'login', 'password'); finally tmpMsg.Free; tmpStringList.Free; end; end;
Мы добавили в процедуру всего две строки кода:
if Form1.Edit1.Text<>'' then tmpMsg.AddPartBinaryFromFile(Form1.Edit1.Text,tmpMIMEPart)
Для того, чтобы отправить на почту файл. При этом указали корневой элемент tmpMIMEPart: TMimePart.
Аналогичным образом в письмо можно добавить любое количество, любых файлов. Остается только добавить, что в Synapse автоматически распознаются следующие MIME-типы и подтипы (по расширению файла):
| Расширение | Тип | Подтип |
| AU | audio | basic |
| MP2 | mpeg | |
| MP3 | mpeg | |
| RA | x-realaudio | |
| SND | basic | |
| WAV | x-wav | |
| MID | midi | |
| AVI | video | x-msvideo |
| MOV | quicktime | |
| MPEG | MPEG | |
| MPG | MPEG | |
| QT | quicktime | |
| DOC | application | MSWord |
| EPS | Postscript | |
| PS | Postscript | |
| RTF | RTF | |
| WPD | Wordperfect5.1 | |
| ZIP | ZIP | |
| BMP | image | BMP |
| GIF | GIF | |
| JPEG | JPEG | |
| JPG | JPEG | |
| PNG | PNG | |
| TIF | TIFF | |
| TIFF | TIFF |
Для всех остальных файлов выставляется тип application с подтипом octet-stream. Если есть желание добавить в библиотеку распознавание других типов файлов, то дополните массив констант MimeType в модуле mimepart.
Быстрое создание и продвижение сайтов в Санкт-Петербурге. Хорошие акции и подарки!
Вроде бы март на дворе, а на улице мороз. В квартире тоже холодно, хоть отопительный котел покупай и обогревайся самомтоятельно.
-----------------------
| Делись! | Загружай! | Плюсуй! |
| | |









03 Дек 2010 в 7:18 пп
Здравствуйте, подскажите, пожалуйста как отправить файл по http методом multipart/form-data? Пытался переделать этот пример, но безуспешно, нигде по этому вопросу информации не нашел.
03 Дек 2010 в 9:56 пп
Так, а в чём там проблема? Вставляете заголовок в запрос, каждую часть разделяете грницей + пустая строка и отправляете.
04 Дек 2010 в 8:43 пп
делаю так:
StringList := TStringList.Create;
tmpMsg := TMimeMess.Create;
Http:=THTTPSend.Create;
tmpMIMEPart := tmpMsg.AddPartMultipart('alternate',nil);
data1:=TStringStream.Create('');
http.Clear;
http.MimeType:='multipart/form-data; boundary=—————————41184676334';
stringlist.Add('method=pos');
stringlist.Add('key=71a046f65057ff99dab062509ab4bad9');
tmpmsg.AddPartMess(stringlist,tmpMIMEPart) ;
tmpmsg.AddPartBinaryFromFile('1.jpg',tmpMIMEPart);
tmpmsg.Lines.SaveToStream(data1);
http.Document.LoadFromStream(data1);
Но отправляется просто пустой post запрос
04 Дек 2010 в 9:00 пп
А зачем вы используете TMimeMess вместе с HTTPSend? Есть же нормальный класс TSMTPSend для отправки писем с вложениями. Это первое. Второе, boudary вы определили, а где используется его значение (boundary=—————————41184676334)? Не проще ли тогда уже использовать код, который я приводил здесь?
08 Дек 2010 в 2:59 пп
Спасибо, разобрался, нашел нужную функцию в демо синапса и немного переделал
function ProxyHttpPostFile(const URL, FieldName, FileName: string;
const Data: TStream; const ResultData: TStrings): Boolean;
const
CRLF = #$0D + #$0A;
var
HTTP: THTTPSend;
Bound, s: string;
begin
Bound := IntToHex(Random(MaxInt), 8) + '_Synapse_boundary';
HTTP := THTTPSend.Create;
try
s := '--' + Bound + CRLF;
s := s + 'content-disposition: form-data; name="method"'+ crlf+ crlf;
s:= s +'post'+crlf;
HTTP.Document.Write(Pointer(s)^, Length(s));
s := '--' + Bound + CRLF;
s := s + 'content-disposition: form-data; name="key"'+ crlf+crlf;
s:= s +'79bfdb771700dbd4bc280fedc0e11111'+crlf;
HTTP.Document.Write(Pointer(s)^, Length(s));
s := '--' + Bound + CRLF;
s := s + 'content-disposition: form-data; name="' + FieldName + '";';
s := s + ' filename="' + FileName +'"' + CRLF;
s := s + 'Content-Type: Application/octet-string' + CRLF + CRLF;
HTTP.Document.Write(Pointer(s)^, Length(s));
HTTP.Document.CopyFrom(Data, 0);
s := CRLF + '--' + Bound + '--' + CRLF;
HTTP.Document.Write(Pointer(s)^, Length(s));
HTTP.MimeType := 'multipart/form-data, boundary=' + Bound;
Result := HTTP.HTTPMethod('POST', URL);
ResultData.LoadFromStream(HTTP.Document);
finally
HTTP.Free;
end;
end;
Может кому пригодится — отправка капчи на сервис antigate
08 Дек 2010 в 3:01 пп
p.s тэг [code] почему-то охватывает не все вложение
15 Янв 2011 в 8:22 пп
Сергей, спасибо! Уже второй раз пригождается, примеров по синапсу в сети крайне мало =(
28 Апр 2011 в 12:47 дп
Столкнулся с интересным приколом Синапса — в некоторых случаях почта НЕ отправляется. Обычно все проходило нормально всегда, пользовал SendToRaw и проблем не было. Единственное почему-то ну душа к TMimeMess не прикипела, в итоге пользую для формирования письма TSakMsg (не пинать — так хочется). Смысл один по любому — объьект формирует текст письма и потом его отправляю.
И вот недавно попалось машин 5-7 которые не могут отправить письмо! Версии полностью идентичные, от операционки данная проблема точно не зависит, т.к. вылазит однозначно на ХР, про другие не помню. Но много других машин с ХР письма отправляют! Общей закономерности пока даже не заметил :-(
Попробовал переписать отправку через обьект TSMTPSend — та же фигня. Правда один клиент сказал что письмо сначала отправилось, но вот второй и третий раз такой фокус не прошел.
Самое большое заподло — на моих компах все работает блин. А ехать к клиентам и ставить там ДЕльфю… Ноненс :-(
Может у кого есть мысли что смотреть хотя бы!