Мы уже рассмотрели, как отправлять простые письма с помощью Win API, теперь давайте изучим способы прикрепления файлов к письму.

Откройте пример из раздела 5.2 и добавьте на форму строку ввода (TEdit) для указания полного имени файла. В предыдущем примере для отправки текста нужно было писать много строк. Это нерационально, поэтому для данного примера я добавил в модуль процедуру SendStr (листинг 5.5).

Листинг 5.5. Функция отправки строки

procedure SendStr(s:TSocket. str.String): 'var
sRecvBuff: array [0..255] of char:
продолжение &

Листинг 5.5 (продолжение) TempStr: AnsiString; begin TempStr := str+#13+#10:

CopyMemory(@sRecvBuff, PChar(TempStr). Length(TempStr)); TestFuncError(send(s, sRecvBuff. Length(TempStr). 0).
'Send Attachment'): TCPClientForm.mmLog.Lines.AddC>'+Copy(TempStr. 1. Pos(#13, TempStr))).
end:

Процедуре достаточно передать сокет и строку для передачи, и она сама сделает все нужные преобразования. Теперь для передачи данных будем пользоваться этой процедурой.

Переходим в процедуру отправки сообщения Здесь нужно заменить код кодировки на следующий:

// Кодировка

SendStKsServerListen. 'Mime-Version: 1.0'):

SendStKsServerListen. 'Content-Туре: multipart/mixed:'):

SendStKsServerListen, 'boundary=" ======sdfgsagg======" ' ) :
SendStKsServerListen. ''):
SendStKsServerListen. '----------=sdfgsagg======' ) :
SendStKsServerListen. 'Content-Type: text/plain: charset="us-ascii"'):
SendStr(sServerLi sten. ' ' ) ;

// Отправка письма

Вначале отправляем серверу версию формата письма. В данном случае это будет также "Mime-Version: 1.0. Теперь посылаем команду, указывающую на тип содержимого. Для простого письма это был text/plain, а в случае с прикрепленными файлами содержимое будет смешанным, то есть тип меняется на multipart/mixed:

SendStKsServerListen, 'Content-Type: multipart/mixed:');

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

boundary = -"Разделитель"

Программа, которая будет расшифровывать письмо, встретив такой разделитель, будет видеть, что началась новая часть или имеется прикрепленный файл. Чаще всего программисты указывают здесь произвольный текст, который не может встретиться в тексте письма или в содержимом файла.

На этом заголовок заканчивается, и мы должны послать серверу пустую строку как разделитель:

SendStr(sServerListen. ''):

Пустая строка отправляется не для красоты, а для того, чтобы отделить заголовок от текста письма.

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

SendStr(sServerListen. ' --========sdfgsagg====='):

Далее размещается текстовый блок. В качестве его типа будет использоваться уже знакомый нам text/plain. После указания типа блока нужно снова отправить пустую строку - если этого не сделать, то получатель сообщения может не увидеть текст:

SendStr(sServerListen. 'Content-Type: text/plain;
charset="us-ascii"'): SendStr(sServerListen. ''):

Затем запускается цикл отправки текста сообщения, и в нем изменений нет. Прикрепленный файл будет отправляться за текстом. Для этого после цикла и до отправки символа конца сообщения пишем следующие строки кода:

// Отправка прикрепления к письму SendStKsServerListen. ''): і f edFi1e.Text <> '' then Ba se64Send(edF і 1e.Text):

Сначала отправляется пустая строка для отделения текста от будущих данных. После этого осуществляется проверка, указан ли файл, и если это так, то вызывается процедура Base64Send. Данная процедура начинает новый блок письма с помощью разделителя и указывает его тип в виде appl і cati on/octet - stream. Содержимое файла отсылается в самой распространенной кодировке Интернета - base64. Текст процедуры Base64Send приведен в листинге 5.6.

Листинг 5.6. Процедура кодирования и отправки файла

procedure Base64Send(FileName: string): var
afile: File;
i: "longint;
quads: integer;
b: array[0..2279] of byte;
j. k. 1, m: integer;
stream: string[76]; begin
AssignFileCafile. filename);
Reset(afile. 1);
SendStr(TCPC1 і entForm. sServerLi sten, ' - -=======sdfgsagg=====');
SendStr(TCPC1і entForm.sServerLi sten. ' Content-Type:
application/octet-stream;
name = '"+ExtractFileName(FileName)+""): SendStr(TCPC1і entForm.sServerLіsten, 'Content-Transfer-Encodi ng:
base64');
SendStr(TCPC1іentForm.sServerListen. 'Content-Disposition:
attachment;
filename = '"+ExtractFileName(FileName)+""): SendStrCTCPClientForm.sServerListen. 'Content-Description: attachment');
SendStr(TCPClientForm.sServerListen. ").-
stream := " : quads := 0:
продолжение &

Листинг 5.6 (продолжение) j := Filesize(afile) div 2280:

for i := 1 to j do
begin
BlockReadCafile. b. 2280): for m := 0 to 39 do begin
for k := 0 to 18 do begin
1 := 57*m+3*k;
stream[quads+l]:=_Code64[(b[l]div 4)+l]. stream[quads+2]:=_Code64[(b[l] mod 4)*16 +(b[l+l] div 16)+1]: stream[quads+3]:=_Code64[(b[l+l] mod 16)*4 +(b[l+2] div 64)+l]; stream[quads+4]:=_Code64[b[l+2] mod 64+1]: IncCquads, 4):
if quads = 76 then begin
stream[0] : = #76; .
SendStr(TCPC1i entForm.sServerL i sten. stream): quads := 0:
. end;
end, end;
end;
j :- (Filesize(afile) mod 2280) div 3:
for i := 1 to j do begin
BlockReadCafile, b. 3);
stream[quads+l] := _Code64[(b[0]div 4)+l]:
stream[quads+2] := _Code64[(b[0] mod 4)*16 +(b[l] div 16)+1]:
stream[quads+3] := _Code64[(b[l] mod 16)*4 +(b[2] div 64)+l];
stream[quads+4] := _Code64[b[2] mod 64+1]; IncCquads, 4);
if quads - 76 then begin
stream[0] := #76;
SendStr(TCPC1ientForm.sServerLi sten. stream);
quads -- 0;
end;
end:
if (Filesize(afile) mod 3) = 2 then begin
BlockReadCafile. b. 2);
stream[quads+l] := _Code64[(b[0]div 4)+l]:
stream[quads+2] := _Code64[(b[0] mod 4)*16 +(b[l] div 16)+1]: stream[quads+3] := _Code64[(b[l] mod 16)*4 +1]; stream[quads+4] := '='; Inc(quads. 4): end:
if (Filesize(afile) mod 3) = 1 then begin
BlockRead(afile, b. 1);
stream[quads+l] -= _Code64[(b[0]div 4)+l]: stream[quads+2] := _Code64[(b[0] mod 4)*16 +1]: stream[quads+3] .- '='; stream[quads+4] := '='; Inc(quads,4):
end:
stream[0] := Chr(quads): if quads > 0 then
SendStr(TCPClientForm.sServerListen, stream): CloseFile(afile):
end:

Файлы, отправляемые через Интернет, могут кодироваться разными способами, поэтому в заголовке нужно указывать тип кодировки (в нашем случае это base64):

SendStKTCPCl і entForm. sServerLi sten.
'Content-Transfer-Encoding: base64'):

Так как в письме будет кодироваться содержимое файла, то его имя может быть передано только через заголовок следующим образом:

SendStr(ТСРС1і entForm.sServerListen.

'Content-Disposition: attachment, filename = "' + ExtractFileName(FileName)+"''):

Команда Content-Di sposition указывает на тип содержимого attachment. После точки с запятой идет параметр filename с указанием имени файла.

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

Снимок почтового клиента, в котором получено письмо с файлом, показан на рис. 5.7.

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

ПРИМЕЧАНИЕ -

Исходный код рассмотренного здесь примера находится на компакт-диске в каталоге Sources\ch05\SMTPFile.

5.3. Отправка файлов по почте

Рис. 5.7. Полученное письмо в почтовом клиенте

5.2.3. Передача больших строк || Оглавление || 5.4. РОРЗ-клиент на Win API


Delphi в шутку и всерьез: что умеют хакеры



Новости за месяц

  • Январь
    2022
  • Пн
  • Вт
  • Ср
  • Чт
  • Пт
  • Сб
  • Вс