Новая версия сайта: The Bat!
Поддержка Simple MAPI
использование Simple MAPI для программирования с помощью theBat!

Simple MAPI это набор интерфейсов и функций, которые обеспечивают доступ к почтовому транспорту и хранилищам данных (таких как адресные книги и сообщения). Этот механизм позволяет принимать/отсылать почту из собственных приложений независимо от конкретного почтового клиента, который будет использоваться.
Все приложения, поддерживающие simple MAPI, должны реализовать двенадцать функций и предоставить три структуры разработчикам. Описание этих функций и список параметров заранее известен и жестко определен.

MAPI является стандартом, который поддерживают многие почтовые клиенты Microsoft Windows. В последних версиях и в TheBat! включена поддержка simple MAPI. Функции и структуры находятся в библиотеке tbmapi.dll.
Если TheBat! установлен, как обработчик запросов simple MAPI по умолчанию, то эта библиотека замещает системную mapi32.dll
Ниже приведен список функций и структур.

ФункцияОписание
MAPIAddress Вывод диалогового окна выбора адресатов
MAPIDeleteMail Удаление письма
MAPIDetails Показ диалогового окна со свойствами конкретного адресата из адресной книги TheBat!. Возможно менять эти свойства с записью в адресную книгу.
MAPIFindNext Выбор "следующего" письма и папки Inbox
MAPIFreeBuffer Освобождение памяти, которая была распределена функциями MAPI
MAPILogoff Завершение сессии MAPI
MAPILogon Открытие очередной сессии MAPI
MAPIReadMail Чтение письма, которое было определено функцией MAPIFindNext
MAPIResolveName Так называемое "разрешение имени адресата" — поиск адреса по имени в адресных книгах.
MAPISaveMail Сохранение письма
MAPISendDocuments Создание письма с приаттаченными файлами
MAPISendMail Создание письма.
СтруктураОписание
MapiFileDesc Информация о приаттаченном объекте.
MapiMessage Параметры и содержимое письма.
MapiRecipDesc Информация об адресате (получателе/отправителе сообщения)

Подробное описание этих функций и их параметров смотрите в соответствующей литературе — MSDN (самое полное и подробное руководство); справка по MAPI, например, есть в стандартной поставке Delphi, файл mapi.hlp. В конце статьи приведен список материалов в сети по этой теме.
Данный материал не является еше одной справкой по simple MAPI, не претендует на абсолютную полноту изложения материала, возможно упущены некоторые нюансы. Данный материал является лишь обобщением собственного опыта.
Я не ставила перед собой цель написать еще одну статью по simple MAPI, мне хотелось рассказать о некоторых особенностях применения этих функций именно при работе с theBAT!, о тех нюансах, с которыми мне пришлось столкнуться. Так как особенности функционирования самого почтового клиента конечно же отражаются на реализации simple MAPI.

MAPIAddress

Выводится диалоговое окно с выбором адресата. Игнорируются некоторые параметры: не учитывается сессия, невозможно изменить надписи в диалоговом окне, не регулируется количество полей для заполнения(по идее это может быть набор из "TO", "CC" и "BCC").
Можно вызвать окно с уже заполненными адресатами.

Пример:
Var P    : PULONG;
    RecN : PMapiRecipDesc;
    Rec  : TMapiRecipDesc;
Begin
	GetMem( RecN , SizeOf(Rec) );

	Rec.lpszName:='';
	Rec.lpszAddress:='info@id.ru';
	Rec.ulEIDSize:=0;
	Rec.lpEntryID:=nil;
	Rec.ulReserved:=0;
	Rec.ulRecipClass:=MAPI_BCC;	
			
	// Выбор инициализируется одним адресом	в поле BCC
	HResult:=MapiAddress(0 , 0 , nil , 0 , nil , 1 , Rec , 0 , 0 , P , RecN );	   
	
	IF HResult = SUCCESS_SUCCESS Then 
	Begin 
		// Были выбраны адресаты
...
	End;
	
	...
	
	MAPIFreeBuffer(RecN);
													 
В итоге, если нажата кнопка [OK], то указатель RecN содержит адрес на первый элемент типа TMapiRecipDesc из списка выбранных адресатов.

MAPIDetails

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

Пример:
Var Rec  : TMapiRecipDesc;
Begin

	Rec.lpszName:='';
	Rec.lpszAddress:='info@id.ru';
	Rec.ulEIDSize:=0;
	Rec.lpEntryID:=nil;
	Rec.ulReserved:=0;
	Rec.ulRecipClass:=0;	
	
	Hresult:=MapiDetails( 0 , 0 , Rec , 0 , 0 );

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

К сожалению нельзя получить доступ к свойствам групп. Хотя в MAPI существует такое понятие, как Personal Distribution List (PDL) , то есть персональный список рассылки, не имеющий собственного адреса.
Ну а группа адресной книги TheBat! соответствует PDL, который является полноправным контейнером адресной книги для MAPI.

MAPIFindNext

Возвращает идентификатор очередного письма из папки Inbox. Необходимо вызывать эту функцию перед вызовом MAPIReadMail.
Пример использования и особенности смотрите в опиаснии функции MAPIReadMail

Стоит напомнить, что интерфейс Simple MAPI осуществляет доступ только к содержимому папки Inbox.

MAPIFreeBuffer

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

MAPILogoff

Завершение сессии.

MAPILogon

Открытие сессии работы с почтовой системой.
Если не использовать эту функцию и далее игнорировать параметр Session, то будет осуществляться работа с тем почтовым ящиком, для которого в TheBat! помечен крыжик "По умолчанию использовать этот ящик для mailto:". Если такого почтового ящика нет, то при попытке отослать или прочитать письмо, будет возвращено значение MAPI_E_LOGIN_FAILURE

Если необходимо выбрать почтовый ящик в процессе работы, то стоит использовать MAPILogon.

Пример:
		
HResult:=MapiLogon(0,'','',MAPI_NEW_SESSION OR MAPI_LOGON_UI,0,Session);
   
или

HResult:=MapiLogon(0,'M T U','111',MAPI_LOGON_UI,0,Session);

или

HResult:=MapiLogon(0,'Ситилайн','',0,0,Session);
Второй параметр это как раз имя нужного почтового ящика, третий параметр — пароль на почтовый ящик, если ящик запаролен.
Если указан флаг MAPI_LOGON_UI, то будет вызвано окно выбора почтового ящика ("select account"). Правда если при наличие этого флага название ящика (и пароль, если надо) заданы корректно, то диалог выбора выводится не будет и сессия откроется для указанного акаунта.
Если название ящика не задано или задано неверно и флаг MAPI_LOGON_UI не установлен, то сессия откроется для того почтового ящика, который установлен "по умолчанию ... для mailto:"

К сожалению в реализации этой функции есть некоторые странные моменты (при работе с запароленым ящиком), о которых сообщено в RITLabs, так что будет ждать пояснений.

MAPIReadMail

Чтение очередного сообщения из папки Inbox. Очередность определяется функцией MAPIFindNext. Смысл в том, чтобы указать, какое именно письмо вам нужно.

Пример:
Var 
    PMess :PMapiMessage;
    PP    : PChar;
Begin
 
	// Читаем самое первое письмо из папки Inbox
	MAPIFindNext(0,0,nil,nil, MAPI_LONG_MSGID OR MAPI_GUARANTEE_FIFO ,0,PP);	
	// Или вот так: читаем следующее письмо после 12-го из папки Inbox
	MAPIFindNext(0,0,nil,'12', MAPI_LONG_MSGID OR MAPI_GUARANTEE_FIFO ,0,PP);	
	MAPIReadMail(0,0,PP,0,0,PMess);

...
 	MAPIFreeBuffer(PMess);

В первом варианте после вызова MAPIFindNext значение РР будет равно '1', во втором варианте — '13'. Конечно, если такие письма в папке есть.
И тогда переменная PMess будет содержать указатель на структуру, заполненную информацией из этого письма.

Есть одна неприятная особенность — две эти функции корректно работают только с нулевой сессией, то есть когда сессия открывается для ящика, который установлен "по умолчанию ... для mailto:"
Не удалось заставить их работать для любого акаунта, если открывать MAPI-сессию функцией MAPILogon.

MAPIResolveName

Так называемое "разрешение имени адресата" — поиск адреса по имени в адресных книгах. В качестве параметра задается имя адресата, в случае его успешного поиска, будет возвращена ссылка на структуру TMapiRecipDesc, содержащую всю информацию о нем.

Пример:

Hresult:=MAPIResolveName(0,0,'jinx',MAPI_DIALOG,0,RecN);

...

MAPIFreeBuffer(RecN);

Если указан флаг MAPI_DIALOG и в адресных книгах найден больше чем один адресат с таким же именем, то будет выведен диалог "разрешения имени":

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

Если такого адресата не найдено, не будет выведен диалог и будет возвращена ошибка MAPI_E_AMBIGUOUS_RECIPIENT независимо от установленных флагов.

MAPISendDocuments
Очень быстрый и простой способ создания стандартного сообщения с прикрепленными файлами и без указания адресов получателей.

Пример:
MapiSendDocuments(0,';','d:\11.txt;d:\22.txt','11.txt;22.txt',0);

или

MapiSendDocuments(Session^,';','d:\11.txt;d:\22.txt','11.txt;22.txt',0);

или

MapiSendDocuments(Session^,';','d:\11.txt;d:\22.txt','',0);

или

MapiSendDocuments(Session^,';','d:\11.txt;d:\22.txt','файл1;файл2',0);
В случае с указанием сессии Session, письмо будет создано для почтового ящика, который открыт в этой сессии (см. MAPILogon), в случае с нулевой сессией — для почтового ящика "по умолчанию..."

Именно эта функция используется, когда вы нажимаете на правую кнопку мыши в проводнике файлов и выбираете меню "Zip and E-mail ... ".

MAPISendMail

Создание и отправка сообщения. В отличии от предыдущей функции здесь задаются все параметры в режиме run-time, таким образом сообщение может быть создано и сразу отправлено без участия пользователя.

Пример:
Var 
	Mess : TMapiMessage;
	Rec  : TMapiRecipDesc;
Begin
						  
    Rec.lpszName:='Информационный центр';
    Rec.lpszAddress:='Info@id.ru';
    Rec.ulEIDSize:=0;
    Rec.lpEntryID:=nil;
    Rec.ulReserved:=0;
    Rec.ulRecipClass:=MAPI_TO;

    Mess.ulReserved:=0;
    Mess.lpszSubject:='';
    Mess.lpszNoteText:='';
    Mess.lpOriginator:=nil;
    Mess.nRecipCount:=1;
    Mess.lpRecips:=RecN;
    Mess.lpszMessageType:=nil;
    Mess.lpszDateReceived:=nil;
    Mess.lpszConversationID:= '';
    Mess.flFlags:=0;
    Mess.nFileCount:=0;
    Mess.lpFiles:=nil;
   
    // Окно редактирования письма будет выдано на экран
    HResult:= MapiSendMail(Session^,0, Mess , MAPI_DIALOG  ,0);
	
    // Или письмо будет сразу после создания отправлено 
    // без вмешательства пользователя	  
    HResult:= MapiSendMail(Session^,0, Mess , 0  ,0);		
	
Все, что касается использования сессии Session смотрите в описании функции MAPISendDocuments

Версии TheBAT! до 1.54 Beta/9 имеют ошибку в реализации функции MapiSendMail, которая не позволяла корректно отсылать письма без участия пользователя. Вариант с флагом MAPI_DIALOG работает корректно во всех версиях.

Елена Филиппова

 
Ссылки по теме:

Новые версии The bat! | Купить The bat! | О проекте | Скачать The Bat!