уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

synapse: работа с вложениями в письмахВот уже больше двух лет прошло с того момента, как я затрагивал в последний раз работу с POP3 в Synapse. Сам-то я к теме работы с почтой отношение имею очень отдаленное и разбирался с TPOP3Send исключительно ради интереса. Однако, тема эта в блоге в последнее время набрала несколько бОльшую популярность нежели я ожидал и даже появились просьбы читателей и посетителей блога о продолжении темы — рассмотреть работу в Synapse с вложениями в письмах. Что ж, спустя два года, возвращаемся к теме работы с почтой в Synapse и посмотрим на работу с аттачментами (attachments) в письмах- посмотрим как определять наличие вложений, их тип, как сочранять их и т.д.

Для того, чтобы лишний раз не повторяться, приведу ссылки на предыдущие посты по работе с TPOP3Send, их всего два: «Synapse. TPOP3Send. Подготовительные работы» и «Synapse TPOP3Send. Обработка писем«.

Введение

Помня о предыдущих дискуссиях относительно работы с почтой вообще, перед началом работы позволю себе напомнить Вам один момент, о котором не стоит забывать, когда Вы начнете сами работать с почтой в Synapse:

Вся информация, изложенная в этой статье касается работы с сервером Mail.ru. Если код, приведенный ниже у Вас по каким-либо причинам не работает — смотрите настройки своих почтовых серверов. Весь код перед публикацией статьи проверяется на работоспособность именно с mail.ru

Почему я обращаю ваше внимание на этот момент? Все довольно просто. Каждый почтовый сервер может быть настроен по-своему — один работает через защищенные соединения, другой нет, один сервер принимает zip-архивы, второй — нет, один ограничивает объем вложений в письме, второй — нет и т.д. и т.п. Исходя из этого, я не ставлю перед собой такой цели как написать в одной статье почтовую программу по-круче The Bat — только показать подход к работе с почтой и все. А для этого работы с одним популярным почтовым сервером вполне достаточно.

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

  1. TPOP3Send — для отправки запросов и получения ответов от сервера
  2. TMimeMess — для работы с почтовым сообщением
  3. TMimePart — для работы с частями почтового сообщения.

Соответственно, в работе буду использоваться три модуля: pop3send.pas, mimemess.pas и mimepart.pas. Напишем небольшое приложение, которое будет выполнять следующие функции:

  1. Авторизовываться и получать количество писем на сервере
  2. Загружать с сервера письмо и получать информацию по нему (количество частей, заголовки и т.д.)
  3. Читать список вложений и сохранять их на диск

Пройдемся по всем пунктам функций нашей будущей программы по порядку.

1. Авторизация на сервере и получение информации о письмах

Этот пункт достаточно подробно рассматривался в первой публикации на тему TPOP3Send, поэтому здесь я приведу только готовый код (с небольшими комментариями) и двинемся дальше.

Вот так у меня сейчас выглядит главная форма приложения:

авторизация на pop3 сервере

Компоненты главной формы для авторизации

Так как я точно знаю, что на данный момент pop3.mail.ru использует порт по умолчанию (110), то не стал добавлять сюда ещё один edit для ввода номера порта.

Клик по кнопке «Login» приводит к выполнению следующего кода:

type
  TForm9 = class(TForm)
    [...]
    procedure btnLoginClick(Sender: TObject);
  private
    Pop3: TPOP3Send;
  public
    { Public declarations }
  end;
 
var
  Form9: TForm9;
 
implementation
 
{$R *.dfm}
 
procedure TForm9.btnLoginClick(Sender: TObject);
begin
  Pop3.TargetHost:=edHost.Text;
  Pop3.UserName:=edLogin.Text;
  Pop3.Password:=edPassword.Text;
  if Pop3.Login then
    begin
      if Pop3.Stat then
        lbMailCount.Caption:=IntToStr(Pop3.StatCount)
      else
        raise Exception.Create('Не удалось получить ответ сервера на команду STAT');
    end
  else
    raise Exception.Create('Соединение не удалось. Проверьте логин/пароль/порт.');
end;

Т.е., если авторизовались на сервере, то сразу запросили информацию по письмам, иначе — сообщаем об ошибке. Переходим к следующему шагу.

2. Загрузка сообщения и его анализ

Эта часть работы будет для нас, видимо, самой важной и интересной. Итак, мы получили количество писем в ящике. Что дальше? Дальше мы должны, в самом простом случае, действовать следующим образом:

  1. Загрузить сообщение с сервера
  2. Декодировать сообщение, например, как это делалось для простых писем, содержащих только текст
  3. Проверить наличие частей сообщения (вложений, текста и т.д.)
  4. Обработать каждую из частей сообщения и получить необходимую нам информацию
  5. Если часть является вложением (файлом) — декодировать вложение и сохранить на диск.

Пройдемся по всему списку задач по порядку.

2.1. Загрузка сообщения с сервера

Объявим в секции private главной формы следующие переменные:

  MailMessage: TMimeMess;

Эта переменная служит для хранения информации о почтовом сообщении. Пока не забыли, в OnCreate и OnDestroy формы пишем:

procedure TForm9.FormCreate(Sender: TObject);
begin
 Pop3:=TPOP3Send.Create;
 MailMessage:=TMimeMess.Create;
end;
 
procedure TForm9.FormDestroy(Sender: TObject);
begin
 MailMessage.Free;
 Pop3.Free;
end;

Теперь, чтобы получить с сервера любое сообщение нам необходимо вызвать метод Retr объекта Pop3:TPop3Send, который получит всё содержимое сообщения и сохранит его в своем свойстве FullResult. Для выполнения Retr необходимо указать индекс сообщения в списке. Индексы писем на сервере мы можем получить, проанализировав все тот же FullResult после выполнения команды LIST с параметром 0. Как это делается — см. всё тот же первый пост по TPOP3Send.

Чем выше индекс сообщения, тем оно новее, т.е. письмо с индексом 1 будет более старым, чем письмо с индексом 10.

Добавляем на главную форму следующие компоненты:

Новые компоненты формы: Label, Edit, Button и ListBox

В ListBox, для наглядности, пока будем выводить все содержимое сообщения. Теперь пишем обработчик кнопки:

procedure TForm9.btnRetrClick(Sender: TObject);
begin
 ListBox1.Items.Clear;
 if Pop3.Retr(StrToInt(edMailIndex.Text)) then
   begin
    MailMessage.Clear;
    MailMessage.Lines.Assign(Pop3.FullResult);
    ListBox1.Items.Assign(Pop3.FullResult);
   end;
end;

Здесь мы сделали следующее: если письмо с заданным индексом было успешно загружено с сервера, то мы передаем все полученные строки из Pop3.FullResult в нашу переменную для последующей обработки. Как это будет выглядеть в работающей программе посмотрим на примере.

2.2. Анализ почтовых сообщений

Себе на ящик я отправил письмо со следующим содержимым:

Письмо с вложениями

При этом самый первый рисунок, прикрепленный к сообщению — это фон письма, а второй и третий файл — это уже нормальные вложения, которые я сам себе решил послать — файл Execl и картинка.

Посмотрим, что вернет нам сервер, когда мы попытаемся сказать это сообщение:

Return-path: 
Authentication-Results: mxs.mail.ru; spf=pass (mx132.mail.ru: domain of gmail.com designates 209.85.217.175 as permitted sender) smtp.mailfrom=any@gmail.com smtp.helo=mail-lb0-f175.google.com;
	 dkim=pass header.i=gmail.com
Received-SPF: pass (mx132.mail.ru: domain of gmail.com designates 209.85.217.175 as permitted sender) client-ip=209.85.217.175; envelope-from=any@gmail.com; helo=mail-lb0-f175.google.com;
Received: from [209.85.217.175] (port=37259 helo=mail-lb0-f175.google.com)
	by mx132.mail.ru with esmtp (envelope-from )
	id 1TeAfU-0000xh-TI
	for any@mail.ru; Fri, 30 Nov 2012 00:25:09 +0400
X-Mru-BL: 0:0:1119
X-Mru-PTR: off
X-Mru-NR: 1
X-Mru-OF: unknown ((Google 2))
X-Mru-RC: US
Received: by mail-lb0-f175.google.com with SMTP id gg13so9218558lbb.34
        for ; Thu, 29 Nov 2012 12:25:08 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=20120113;
        h=message-id:date:from:to:subject:references:mime-version
         :content-type;
        bh=yJ2c4ft9WbyhvYpYgpEKFZ386vDz4LVBeWzZ99Nrvag=;
        b=fUnFNbGp0r/+piP8XxO2YwF2RYTZ
         FIC0t79Boeg/IlTELK+0C2pnFzkEIEg1IfZTpm8D/TGOWQC+YyRichxI77WDAMrboqJj
         Kr3MmXd7Rl/Z5b+Yq9x0ZF4VqjB1B/Po2wc+mxv+pC6d+5YbnJEjEGxVBBHziLma15uT
         +2fQ==
Received: by 10.112.36.137 with SMTP id q9mr10266416lbj.42.1354220708288;
        Thu, 29 Nov 2012 12:25:08 -0800 (PST)
Received: from Vlad-PK ([23.23.23.23])
        by mx.google.com with ESMTPS id sj3sm1126331lab.2.2012.11.29.12.24.58
        (version=SSLv3 cipher=OTHER);
        Thu, 29 Nov 2012 12:25:04 -0800 (PST)
Message-ID: 
Date: Fri, 30 Nov 2012 03:24:57 +0700
From: "Vlad" 
To: =?utf-8?B?ItCS0LvQsNC00LjRgdC70LDQsiDQktC40LrRgtC+0YDQvtCy0LjRhyDQkdCw0LbQtdC90L7QsiI=?=

Subject: =?utf-8?B?0J/QuNGB0YzQvNC+INGBINCy0LvQvtC20LXQvdC40Y/QvNC4?=
References: EDSK2012113003232600000057
MIME-Version: 1.0
Content-Type: multipart/mixed;
	boundary="=NextPart_2012113003232600000058"
X-Spam: Not detected
X-Mras: Ok
X-Mru-Authenticated-Sender: any@gmail.com

--=NextPart_2012113003232600000058
MIME-Version: 1.0
Content-Type: multipart/related;
	type="multipart/alternative";
	boundary="----=_NextPart_000_0000_38A0777C.7CA6C970"

------=_NextPart_000_0000_38A0777C.7CA6C970
Content-Type: multipart/alternative;
	boundary="----=_NextPart_001_0000_46AC7537.378F2A18"

------=_NextPart_001_0000_46AC7537.378F2A18
Content-Type: text/plain;
	charset="utf-8"
Content-Transfer-Encoding: base64

0K3RgtC+INC/0LjRgdGM0LzQviDRgdC+0LTQtdGA0LbQuNGCINCy0LvQvtC20LXQvdC40Y86INGE
0LDQudC7IEV4ZWNsINC4INC60LDRgNGC0LjQvdC60YM=
------=_NextPart_001_0000_46AC7537.378F2A18
Content-Type: text/html;
	charset="utf-8"
Content-Transfer-Encoding: quoted-printable

[много текста+HTML]
------=_NextPart_001_0000_46AC7537.378F2A18--

------=_NextPart_000_0000_38A0777C.7CA6C970
Content-Type: image/jpeg
Content-Transfer-Encoding: base64
Content-ID: 

/9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAARgAA/+4ADkFkb2JlAGTAAAAAAf/b
AIQABAMDAwMDBAMDBAYEAwQGBwUEBAUHCAYGBwYGCAoICQkJCQgKCgwMDAwMCgwMDQ0MDBERERER
[много-много букв]
FBQUFBQUFBQUFAEEBQUIBwgPCgoPFA4ODhQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU
FBQUFBQUFBQUFBQUFBQUFBQU/8AAEQgCWAMgAwERAAIRAQMRAf/EAF8AAQEBAQEAAAAAAAAAAAAA
AAABAgMIAQEBAQEBAAAAAAAAAAAAAAAAAQIEAxABAQEBAAMBAAMBAAAAAAAAAAERAiExEkFRYXGR
gAAAAAAAqKAogCooAAACKGgaIaCaBoGgaKaAqIAAAAAACgCoIAAAaCaCWqiaqpaIzaqpaIzaDN6U
S9KM6DNqolqjOgn0CaBqiaBoGgaBoGgAaC6BoKABoLqDWoLKKaDWsjUoLKC6CxFaBqXEF0GpUF2I
qjJoqCioIICygagKIABoAGgaAACqAP/Z
------=_NextPart_000_0000_38A0777C.7CA6C970--

--=NextPart_2012113003232600000058
Content-Type: application/vnd.ms-excel;
	name==?utf-8?B?0L/RgNC40LzQtdGAICgyKS54bHM=?=
Content-Disposition: attachment;
	filename==?utf-8?B?0L/RgNC40LzQtdGAICgyKS54bHM=?=
Content-Transfer-Encoding: base64

0M8R4KGxGuEAAAAAAAAAAAAAAAAAAAAAPgADAP7/CQAGAAAAAAAAAAAAAAACAAAA6wAAAAAAAAAA
IHJlcXVpcmVkIHRvIHVzZSB0aGUgcHJvZ3JhbS4OAABzdHJOZXdEb2N1bWVudAwAAE5ldyBEb2N1
IABFAG4AdAByAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW
[много-много букв]
AAAAAAAAAAAAAAAATbEBAAAAAAAFAFMAdQBtAG0AYQByAHkASQBuAGYAbwByAG0AYQB0AGkAbwBu
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAACAQEAAAADAAAA/////wAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAANkAAAAAEAAAAAAAAAUARABvAGMAdQBtAGUAbgB0AFMAdQBt
AG0AYQByAHkASQBuAGYAbwByAG0AYQB0AGkAbwBuAAAAAAAAAAAAAAA4AAIB////////////////
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4QAAAAAQAAAAAAAA
--=NextPart_2012113003232600000058
Content-Type: image/png;
	name="with_error (2).PNG"
Content-Disposition: attachment;
	filename="with_error (2).PNG"
Content-Transfer-Encoding: base64

iVBORw0KGgoAAAANSUhEUgAAAocAAAIECAYAAABrMISUAAAAAXNSR0IArs4c6QAAAARnQU1BAACx
jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAP+lSURBVHhe7P096HVbdt6JVuDAQQcVOKigAwsc
[много-много букв]
SlERpvSBUiNnyDtVQwojR/5Sq9GoHAKkodpHf2dfRPCDvzFETHmyHeKuvFfZFhekTmUwz7PyBffY
g5xCqY7WMdzOmoBgnFuPZ0jzgPHdCmUb74rQrfkjc/wR8JyDC9WoDAAzMvIYfsQ50DjGI3c8Q7Jw
Xhzxy7DuoVDkbuUSoxYqqJ0ZQAEOQsfKHXpPRd0jpxzsUz6/DiHPY+7ze7VHoAe2a+37aD/ifIci
iM8n21H7cbKn0Kc+gsPLk8KOa0Jbw9jKItiwEOVQcvDE4zgbIPJzeWiYq6ChURfaHXAG0ESQGZ+z
--=NextPart_2012113003232600000058--

Что из себя представляет формате multipart/form-data мы уже в знаем ещё с момента работы с THTTPSend. Теперь, достаточно взглянуть на код почтового сообщения выше и увидеть очень много похожих вещей. В сообщении определены границы (boundary), которыми отделяется каждая часть сообщения. Для каждой части совершенно однозначно определен тип контента и способ его кодировки и при этом используются все те же заголовки, которые мы активно использовали при работе с HTTP. Посмотрев на сообщение ещё внимательнее, можно сказать, что

каждая часть почтового сообщения может содержать в себе другие части

Например, часть с текстовым содержимым содержит в себе и картинку (фон).

Как разобрать письмо по частям и проанализировать каждую? Вариантов опять же масса, но рассмотрим мы такой — воспользуемся событиями у TMimePart, а точнее одним событием

property OnWalkPart: THookWalkPart read FOnWalkPart write FOnWalkPart;

Это событие срабатывает каждый раз, когда мы начинаем «гулять» по какой-либо части сообщения. THookWalkPart имеет следующее описание:

THookWalkPart = procedure(const Sender: TMimePart) of object;

Для наглядности положим на форму ещё один ListBox и TreeView, чтобы форма стала выглядеть вот так:

Главная форма приложения

И напишем такой обработчик события OnWalkPart:

procedure TForm9.Walk(const Sender: TMimePart);
  function GetLastNodeOnLevel(ALevel: integer): TTreeNode;
  var
    I: integer;
  begin
    with MessageTree do
      for I := 0 to Items.Count - 1 do
      begin
        if Items[I].Level = ALevel then
          if (pos('MessagePart Level#', Items[I].Text) > 0) or
            (pos('Root', Items[I].Text) > 0) then
            Result := Items[I].Parent.GetLastChild;
      end;
  end;
 
  procedure ProcessPart(Node: TTreeNode; Part: TMimePart);
  begin
    with MessageTree do
    begin
      Items.AddChild(Node, 'SubLevel: ' + IntToStr(Part.SubLevel));
      Items.AddChild(Node, 'Encoding: ' + Part.Encoding);
      Items.AddChild(Node, 'Charset: ' + Part.Charset);
      Items.AddChild(Node, 'Primaty: ' + Part.Primary);
      Items.AddChild(Node, 'Secondary: ' + Part.Secondary);
      Items.AddChild(Node, 'Disposition: ' + Part.Disposition);
      Items.AddChild(Node, 'ContentID: ' + Part.ContentID);
      Items.AddChild(Node, 'Boundary: ' + Part.Boundary);
      Items.AddChild(Node, 'FileName: ' + Part.FileName);
      Items.AddChild(Node, 'SubParts: ' + IntToStr(Part.GetSubPartCount));
    end;
  end;
 
begin
  Sender.DecodePart;
  if Sender.SubLevel = 0 then
    MessageTree.Items.AddChildFirst(MessageTree.Items[0], 'Root Part')
  else
    ProcessPart(MessageTree.Items.AddChild(GetLastNodeOnLevel(Sender.SubLevel),
      'MessagePart Level#' + IntToStr(Sender.SubLevel)), Sender);
  WalkList.Items.Add(IntToStr(Sender.SubLevel));
end;

Рассмотрим этот обработчик подробнее.
Вначале мы разбираем (декодируем) полученную часть, для чего вызываем метод DecodePart.

Sender.DecodePart;

Далее идёт проверка значения свойства SubLevel. SubLevel — это уровень вложенности части сообщения. Как я уже говорил ранее — любая часть сообщения может иметь различно количество подчастей с различным уровнем вложенности. У сообщения всегда есть одна часть с SubLevel = 0 и может быть неограниченное количество частей с SubLevel = 1,2,3 и т.д. Вот мы и проверяем — если SubLevel = 0, то мы находимся в корне сообщения и соответственно, добавляем в дерево узел с текстом «Root Part», если нет, то выполняем следующие действия:
Ищем самый последний узел в дереве с уровнем вложенности равным SubLevel:

  GetLastNodeOnLevel(Sender.SubLevel)

Далее добавляем новый дочерний узел к найденному, указав при этом SubLevel части в названии узла:

MessageTree.Items.AddChild(GetLastNodeOnLevel(Sender.SubLevel),'MessagePart Level#' + IntToStr(Sender.SubLevel))

Заполняем данные по полученной части:

ProcessPart(MessageTree.Items.AddChild(GetLastNodeOnLevel(Sender.SubLevel),
      'MessagePart Level#' + IntToStr(Sender.SubLevel)), Sender);

Методы GetLastNodeOnLevel и ProcessNode описаны выше и подробно рассматривать мы их не будем. В заключении мы выводим во второй ListBox значение SubLevel части с которой работали, чтобы наглядно увидеть как происходит обход дерева сообщения.

Не стоит забывать, что почтовое сообщение может состоять только из одной части (корня), например, если отправляется простой PlainText

Теперь, когда у нас есть обработчик «прогулки» по сообщению, можно дописать обработчик кнопки получения сообщения. Весь код обработчика будет таким:

procedure TForm9.btnRetrClick(Sender: TObject);
begin
  ListBox1.Items.Clear;
  WalkList.Items.Clear;
  if Pop3.Retr(StrToInt(edMailIndex.Text)) then
  begin
    ListBox1.Items.Assign(Pop3.FullResult);
    MailMessage.Clear;//чистим от предыдущей информации
    MailMessage.Lines.Assign(Pop3.FullResult);//записываем сообщение
    MailMessage.DecodeMessage;//декодируем
    MailMessage.MessagePart.OnWalkPart := Walk;//назначаем обработчик
    MailMessage.MessagePart.WalkPart;//"гуляем" :)
  end;
end;

Здесь мы стартуем, как и необходимо, с самой первой части сообщения (с корня). Вот, например, какой результат мы получим, если попробуем обойти части сообщения код которого я приводил выше:

Результат

Результат обхода сообщения

А казалось бы — отправил всего лишь пару строк текста с фоновой картинкой и два файла. А получил (вместе с корнем) восемь частей сообщения.

Теперь посмотрим, что мы получили в итоге после прохождения по всем частям сообщения.

Encoding — тип кодирования части. Часть сообщения может кодироваться как Base64, Quoted-Printable и т.д. Это свойство записывается на основании значения в свойстве EncodingCode, которое может принимать одно из следующих значений:

TMimeEncoding = (ME_7BIT, ME_8BIT, ME_QUOTED_PRINTABLE, ME_BASE64, ME_UU, ME_XX)

Charset — кодировка текста (UTF-8, WINDOWS-1251 и т.д.).
Primary — Mime-тип части. Записывается на основании значения в свойстве PrimaryCode, которое может принимать следующие значения:

TMimePrimary = (MP_TEXT, MP_MULTIPART, MP_MESSAGE, MP_BINARY);

Secondary — значение Type из заголовка Content-Type части. Например, в моем письме была часть с таким заголовком:

Content-Type: multipart/related;
	type="multipart/alternative";

В этом случае Primary=»multipart», а Secondary = «alternative».

Disposition — расположение части в сообщении. Может принимать значения «ATTACHMENT», «INLINE» или содержать пустую строку.

ContentID — идентификатор части. Может отсутствовать в заголовках.

Boundary — разделитель, который используется в части для разделения своих подчастей. Соответственно, если подчастей нет, то это свойство содержит пустую строку.

FileName — содержит имя файла, если часть является вложением

GetSubPartCount — метод который получает количество подчастей для части.

Вот теперь, имя в руках эту информацию мы уже можем сказать о том, как определить, что письмо содержит вложения.

Во-первых, вложения всегда имеют в свойстве Disposition значение ATTACHMENT.

Во-вторых, вложение всегда имеет свое названия (имя файла).

Теперь разберемся как эти вложения можно сохранять на диск.

2.3. Сохранение вложений

У нас уже есть обработчик для OnWalkPart — им мы и воспользуемся для сохранения вложений. Чтобы правильно сохранить вложение нам необходимо выполнить как минимум одно условие: правильно декодировать вложение.

Допишем нашу процедуру Walk следующим образом:

uses SynaCode;
[...]
var Stream: TStringStream;
begin
[...]  
WalkList.Items.Add(IntToStr(Sender.SubLevel));
 
  if SameText(Sender.Disposition,'attachment') then
    begin
      Stream:=TStringStream.Create;
      try
        Stream.WriteString(DecodeBase64(Sender.PartBody.Text));
        Stream.SaveToFile(Sender.FileName);
      finally
        Stream.Free;
      end;
    end;
end;

Здесь мы воспользовались методом DecodeBase64 из модуля SynaCode, записали декодированную строку в поток, а поток сохранили в файл. В итоге на диске рядом с exe-файлом у меня оказалось два файла (а не 3 как показал mail.ru), т.к. всего две части сообщения были отмечены как attachment. Оба файла прекрасно открылись и прочитались.

Вот и все, что хотелось рассказать про вложения в письмах. Остается только поделиться исходниками:

и сказать — До новых встреч :)

Книжная полка

Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
23 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Александр
30/11/2012 13:50

Новый дизайн? Мне нравится :)

trackback

[…] Vladislav Bajenov writes about how to work with email attachements in Delphi […]

Evgeny Popov
11/12/2012 20:23

А можно ли как то читать заголовки писем без их скачивания?
Т.е. чтоб найти письмо по заголовку (+ отправителю)?

Konstantin
Konstantin
15/12/2012 18:57

Скажите пожалуйста, а как определить что хост доступен, если я днлаю коннект через Soks proxy ?
Т.е. вылезает ошибка Host not found но непонятно, то ли прокси дохлый, то ли до сервера не достучаться ?

Konstantin
Konstantin
15/12/2012 21:43
Ответить на  Vlad

А в самом компоненте FTPSend или POPSend можно это как то получить, чтобы не делать два коннекта подряд ?

sergej
sergej
20/03/2013 02:15

Vlad, доброго времени суток. Во первых БОЛЬШУЩЕЕ спасибо за статью про SMTP! Заработал DSN! Но теперь встала еще одна гадкая проблема. У нас почтарь Exchange и ему надо pop3 на 110 порту + starttls + аутентификация по NTLM. И тут-то я и приплыл… Подскажите плиз компонент (желательно фришный) который бы умел рор3 с такими извращениями… Или я плохо смотрел и synapse и это умеет?

sergej
sergej
21/03/2013 01:09

Влад, доброго времени суток. Рыская по инету в поисках решения случайно наткнулся… http://cryptocode.ru/synapse/NTLMAuthDemoApps_Synapse38b2.zip Счас вот сижу пытаюсь попробовать. О рез-ах отпишусь, если разбирусь… :)

sergej
sergej
27/03/2013 16:38
Ответить на  sergej

Отвечаю.. Все работает! Правда, не понятно почему только при автоирзации pop3authlogin, хотя на сервере exchange стоит ntlm… Но разбираться я не стал, главное, что все что мне требвалось от synapse заработало. Влад, еще раз огромное вам спасибо за ценные материалы!

Andrew
Andrew
24/01/2014 13:06

Подскажите пожалуйста в чем может быть проблема: Скачал ваш проект, пытаюсь открыть его в D7 вышла ошибка vcl.forms.dcu not found
Поможете разобраться?

Andrew
Andrew
28/01/2014 09:35
Ответить на  Vlad

После того как удалил VCL. появились еще ошибки…. помогите пожалуйста их решить.
[Warning] main.pas(112): Return value of function ‘GetLastNodeOnLevel’ might be undefined
[Error] main.pas(143): Not enough actual parameters
[Error] main.pas(146): Undeclared identifier: ‘SaveToFile’
[Error] main.pas(155): Undeclared identifier: ‘ReportMemoryLeaksOnShutdown’
[Hint] main.pas(39): Private symbol ‘mimepart’ declared but never used
[Fatal Error] pop3.dpr(5): Could not compile used unit ‘main.pas’

Andrew
Andrew
28/01/2014 09:38
Ответить на  Vlad

[Warning] main.pas(112): Return value of function ‘GetLastNodeOnLevel’ might be undefined
[Error] main.pas(143): Not enough actual parameters ->ошибка в строке Stream:=TStringStream.Create;
[Error] main.pas(146): Undeclared identifier: ‘SaveToFile’ -> ошибка в строке Stream.SaveToFile(Sender.FileName);
[Error] main.pas(155): Undeclared identifier: ‘ReportMemoryLeaksOnShutdown’ -> ошибка в строке ReportMemoryLeaksOnShutdown := True;
[Hint] main.pas(39): Private symbol ‘mimepart’ declared but never used
[Fatal Error] pop3.dpr(5): Could not compile used unit ‘main.pas’

Vladimir
Vladimir
23/05/2014 17:13
Ответить на  Vlad

Можно не использовать TStringStream, а заменить его на TMemoryStream вот так:

MyStream:= TMemoryStream.Create;
try MyStream.Write(PChar(DecodeBase64(Sender.PartBody.Text))^,Length(DecodeBase64(Sender.PartBody.Text)));
MyStream.SaveToFile(Sender.FileName);
finally
MyStream.Free;
end;

Юра
Юра
05/02/2014 13:50

С свойством Disposition не верно подмечено автором:

«Во-первых, вложения всегда имеют в свойстве Disposition значение ATTACHMENT.»

Про Disposition немного описано здесь. У меня был случай, когда свойство Disposition для вложения (excel файлы) имели значение INLINE.

андрей
андрей
17/07/2014 12:06

Кто подскажет, как с помощью Synapse разобрать Winmail.dat (TNEF)?