Продолжаем разговор о почтовой системе Windows. CDO для Windows 2000 — новый API для работы с SMTP и NNTP сервисами NT. Check this out.
Краткий обзор технологий
Приходилось ли вам программно отправлять почту или получать доступ к сообщениям вашего почтового ящика? Если вы программировали эти задачи на Visual C++, то наверняка вам знаком интерфес MAPI. Но о нем говорить, к счастью, не будем.
Bо времена Exchange 5.0 cуществовал и более легкий способ работы с почтовыми сообщениями — при помощи библиотеки OLEMSG32, которая по сути была COM оберткой для MAPI. С появлением Exchange 5.5 Microsoft сменил название библиотеки, сделав его весомым и кратким — CDO (Collaboration Data Object). Функциональность же принципиально не изменилась.
Библиотеки CDO ранних версий ( CDO v 1.x ) основывались на интерфейсах MAPI, и предоставляли разработчикам способы управления почтовыми сообщениями проще чем MAPI. За счет этого программирование при помощи CDO стало популярно среди разработчиков. Для доступа к компонентам SMTP и NNTP, входящим в состав IIS 4.0 появилась библиотека CDONTS — специализированное подмножество CDO.
Вместе с Windows 2000 вышла библиотека CDO 2.0 или CDO for Windows 2000. Основой для нее явились принципиально новые решения: поддержка Internet-стандартов и стандартизация доступа к данным через OLE DB/ADO интерфейс. Известно, что операционная система Windows 2000 активно использует эту библиотеку для своих задач.
С выходом Exchange 2000 на свет появилась еще несколько библиотек CDO — 3.0 или CDO for Exchange 2000, CDO for Exchange Management и CDO Workflow Objects for Exchange. CDO for Exchange естественно расширяет функциональность CDO for Windows. С помощью CDO 3.0 возможна разработка программных решения на базе Web Store. А наличие механизмов перехвата транспорнтых событий и событий от операций с даннымии ( transport and store event) позволяет расширять функциональность Web Store.
Примечание: Web Store — одна из ключевых инициатив Microsoft для унификации доступа к данным. Web Store комбинирует функциональность файловой системы, Web — доступа и процедур коллективной работы.
Далее не будем вспоминать, что было в веке минувшем и подробнее остановимся на версиях CDO, поставляемых с продуктами Microsoft версии 2000.
Основные черты CDO for Windows 2000 (CDOSYS.DLL)
- Для работы через CDOSYS необходимы ОС Windows 2000 и сервер SMTP ( локальный или удаленный ). Возможна программная настройка на SMTP сервер.
- Поддержка транспортных событий. События протоколов для входящей и исходящей почты и новостей. Поддержка Internet — стандартов.
- Создание и управление данными в форматах MIME/MHTML. Поддержка отправки/приема сообщений через SMTP/NNTP протоколы.
- Стандартизованный доступ к данным. CDOSYS основана на технологии доступа к данным OLE DB/ADO.
- Поддержка языков программирования. CDOSYS — это COM библиотека, поддерживающая дуальный интерфейс, что позволяет использовать ее во многих языках программирования: Visual Basic, VB Scripting Edition, Java Script, Visual Basic for Application, Visual C++.
- Возможность обновления библиотеки. CDOSYS разрабатывалась как подмножество библиотеки CDO for Exchange (CDOEX). Поэтому поддерживается полная программная совместимость приложений, разработанных для CDOSYS после установки Exchange 2000.
Cценарии применения CDOSYS.DLL
- Массовые рассылки. Создание шаблонов сообщений.
- Репликации, основанные на почтовых сообщениях. Например, Windows 2000 использует CDOSYS для репликаций Active Directory.
- Проверка на наличие вирусов в почтовых сообщениях и новостях перед доставкой получателю.
- Выявление spam — сообщений перед доставкой получателю.
- Отправка Web — страниц, включая ссылки и графику по запросам пользователей. Например, организация подписки на страницы с новостями.
- Формирование и отправка сообщений, подтверждающих завершение транзакций.
- Автоматическая пересылка входящей почты.
- Административные сообщения.Например, периодическая отправка сообщений о состоянии серверов/сервисов в почтовый ящик системного администратора.
Основные черты CDO for Exchange Server 2000 (CDOEX.DLL)
- Расшираяет функциональность CDO for Windows. Поддерживается программная совместимость с CDOSYS.
- Управление календарем через CDOEX. Протокол работы c кадендарем основан на стандартах Internet (iCalendar). Поддерживается полная совместимость с календарем Outlook 98 и Outlook 2000.
- Разделение функциональности. ADO используется для навигации по данным а CDO для связывания с Web Store.
- Создание пользовательских объектов CDO. CDOEX позволяет имплементировать базовые объекты CDO при создании пользовательских CDO объектов.
- Дополнительные библиотеки для Exchange Server 2000. Библиотека CDOEXM — CDO for Exchange Mangement Libraries предоставляет объекты и интерфейсы для управления сервером и почтовыми ящиками Exchange Server. Для обеспечения доступа к Active Directory Microsoft рекомендует использовать эту библиотеку соместно с интерфейсами ADSI (Active Directory Service Interfaces). Еще одна новая библиотека CDOWF служит для управления объектами Exchange Workflow Engine.
Версии CDO
Exchange 5.0 | Exchange 5.5 | IIS 4.0 | Windows 2000 Server | Exchange 2000 | |
---|---|---|---|---|---|
Active Messaging |
Да |
Нет |
Нет |
Нет |
Нет |
CDO 1.2 |
Нет |
Да |
Нет |
Нет |
Да |
CDO 1.2 for Windows NT Server |
Нет |
Да |
Да |
Да* |
Да* |
CDO for Windows 2000 Server |
Нет |
Нет |
Нет |
Да |
Нет |
CDO for Exchange 2000 |
Нет |
Нет |
Нет |
Нет |
Да |
* — поддерживается для совместимости с существующими приложениями.
Примеры создания объектов библиотеки CDO в разных языках программирования
VbScript
Dim iMsg Set iMsg = CreateObject("CDO.Message") Dim iDsrc Set iDsrc = iMsg.DataSource Dim iBp Set iBp = iMsg.BodyPart
Visual Basic
Предварительно необходимо установить ссылки на Microsoft CDO for Microsoft Windows 2000 Library Microsoft ActiveX Data Objects 2.5 Library
Dim iMsg As New CDO.Message ...
Visual C++
Если вы хотите работать с объектами CDOSYS на языке С++, используя только COM, то основа программы будет выглядеть следующим образом:
#import "c:program filescommon filessystemadomsado15.dll"
no_namespace raw_interfaces_only #import "cdosys.dll" no_namespace raw_interfaces_only /* Флаг raw_interfaces_only запрещает создание классов - оберток для использования "смарт-поинтеров". По флагу no_namespace не просиходит генерации компилятором пространста имен. */ #include "с:sdkincludecdosysstr.h" #include "с:sdkincludecdosyserr.h" #include <assert.h> void main() { CoInitialize(NULL); IMessage* pMsg = NULL; HRESULT hr = CoCreateInstance(__uuidof(Message), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMessage), reinterpret_cast<void**>(&pMsg)); assert(SUCCEEDED(hr)); Fields* pFlds = NULL; pMsg->get_Fields(&pFlds); ... CoUninitialize(); }
Важное замечание
Обязательно нужно использовать ADO 2.5 в глобальном пространстве имен или в пространстве имен CDO. Иначе по умолчанию параметры в функциях CDO из пространства имен ADO не будут корректно разрешены при компиляции.
Пример использования классов — оберток
#import "c:program filescommon filessystemadomsado15.dll"
no_namespace #import
"c:program filescommon filesMicrosoft SharedCDOcdoex.dll" no_namespace #include "cdoexstr.h" #include "cdoexerr.h" void main() { CoInitialize(NULL); { try { IMessagePtr iMsg(__uuidof(Message)); FieldsPtr Flds; Flds = iMsg->Fields; : } catch( _com_error err) { // ... } } CoUninitialize(); return 1; }
Объектная модель CDO 2.0
- IBodyPart — содержит абстрактные методы и свойства для управления секции тела сообщения.
- IMessage — содержит абстрактные методы и свойства для управления сообщением в целом.
- IDataSource — содержит абстрактные методы и свойства для связывания и упорядочивания, выделения и вставки данных сообщений в другие объекты или из них.
- IDropDirectory — содержит методы доступа к сообщениям, хранящимся в файловой системе (например в Windows 2000 SMTP drop directory).
- IMessages — содержит интерфейс коллекции сообщений.
- IBodyParts — содержит интерфейс коллекции секций сообщения.
Аннотация
Библиотеки объектов данных совместной работы (все версии) используются для реализации функций обмена сообщениями и совместной работы в настраиваемом приложении. В этой статье приведены сведения о том, где можно найти эти библиотеки.
Дополнительная информация
Библиотеки динамической компоновки (DLL) для объектов CDO (1,1, 1,2, 1,21) и CDO (1,1, 1,2) — это клиентские библиотеки объектов MAPI. Таким образом, для них требуются MAPI и поставщики услуг (например, те же поставщики услуг, что и в Microsoft Exchange Server).
Объекты совместной работы для NTS (CDONTS) — это простой протокол передачи почты (SMTP), который является частью общей библиотеки CDO (1,1, 1,2), но не зависит от MAPI.
Объекты совместной работы для Windows 2000 (CDOSYS) — это тактовый скачок в обмене сообщениями SMTP через CDONTS. CDOSYS обеспечивает обширный контент с помощью расширенной поддержки MIME.
Имена этих файлов варьируются в зависимости от версии CDO, как указано в приведенной ниже таблице.
Версия |
Библиотека сообщений |
Отрисовка библиотеки |
CDO для NTS |
CDO для Win2K |
---|---|---|---|---|
v1.1 |
Olemsg32.dll |
Amhtml.dll |
Cdonts.dll |
n/a |
v1.2 |
Cdo.dll |
Cdohtml.dll |
Cdonts.dll |
n/a |
v1.21 |
Cdo.dll |
Cdohtml.dll |
n/a |
n/a |
v6.0 |
n/a |
n/a |
n/a |
Cdosys.dll |
Эти файлы можно получить при установке следующих продуктов:
v1.1 |
v1.2 |
v1.21 |
v6.0 |
ПУСТИВ |
RND |
NTS |
ПУСТИВ |
||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
RND |
NTS |
ПУСТИВ |
RND |
NTS |
ПУБЛИКАЦИИ |
||||||||||
Outlook 8,00 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
|||||
Клиент Exchange 5,0 |
Д |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
|||||
Outlook 8.01 — 8.03 |
Д |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
|||||
Сервер Exchange 5,0 |
Д |
Д |
Д |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
|||||
IIS 4,0 |
.Nn- |
.Nn- |
Д |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
|||||
Outlook 98 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
.Nn- |
.Nn- |
.Nn- |
|||||
Сервер Exchange 5,5 |
.Nn- |
.Nn- |
.Nn- |
Д |
Д |
Д |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
|||||
Exchange 5,5 Server SP1 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
Д |
Д |
.Nn- |
.Nn- |
.Nn- |
|||||
Сервер Exchange 5,5 с пакетом обновления 2 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
Д |
Д |
.Nn- |
.Nn- |
.Nn- |
|||||
Outlook 2000 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
.Nn- |
.Nn- |
.Nn- |
|||||
Outlook 2002 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
.Nn- |
.Nn- |
.Nn- |
|||||
Outlook 2003 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
.Nn- |
.Nn- |
.Nn- |
|||||
Windows 2000 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
|||||
Exchange 2000 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
Д |
.Nn- |
.Nn- |
|||||
Exchange 2000 SP1 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
Д |
.Nn- |
.Nn- |
|||||
Exchange 2000 SP2 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
Д |
.Nn- |
.Nn- |
|||||
Exchange 2000 SP3 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
Д |
.Nn- |
.Nn- |
|||||
Windows 2003 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
|||||
Exchange 2003 |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
.Nn- |
Д |
.Nn- |
.Nn- |
.Nn- |
Начиная с Microsoft Exchange Server 2007 Beta 2, в них не включены клиентские библиотеки API обмена сообщениями (MAPI) и CDO 1.2.1. Таким образом, функции отсутствуют, и многие приложения зависят от этих функциональных возможностей. Microsoft Exchange MAPI и CDO 1.2.1 предоставляют доступ к этим API. Эти API предоставляют доступ к содержимому хранилищ MAPI.
Примечание. Поскольку эта версия CDO входит в состав Exchange 2003, мы не поддерживаем установку этой версии на компьютере с установленным приложением Outlook. Дополнительные сведения см. в следующей статье базы знаний Майкрософт:
266418 Корпорация Майкрософт не поддерживает установку компонентов Exchange Server и Outlook на одном и том же компьютере
Для компьютеров, использующих Outlook 2010, использование CDO не поддерживается. Для получения дополнительных сведений обратитесь к следующей статье Microsoft Knoowledge Base:
Объекты данных совместной работы (CDO) 1.2.1 не поддерживаются в Outlook 2010
Примечание. Компонент CDO версии 1.2.1 ссылается на версию API, которая не является версией DLL, реализующей API. Библиотека DLL, содержащаяся в Outlook 2007 CDO download, имеет версию 6,5. Это не обновление CDOSYS, на которое ссылается эта статья, как версия 6,0.
При использовании Exchange для установки CDO 1,21 можно использовать один из указанных ниже способов для установки.
-
Установка Exchange Server (Exchange 5,5, 2000 и 2003)
-
Установка только служебной программы Exchange Administrator (или Exchange System Manager) (Exchange 5,5, 2000 и 2003)
-
Установка Outlook Web Access (OWA — только Exchange 5,5)
После установки может потребоваться вручную зарегистрировать CDO. dll с помощью Regsrv32 (то есть Regsrv32. exe полный путь и имя файла для CDO. DLL). Для установки Exchange System Manager необходимо скопировать файл CDO. dll с установочного носителя в каталог% Program Files%/Exchsrvr/Bin, прежде чем регистрировать CDO. dll с помощью Regsrv32. exe.
По умолчанию установки Outlook не включают компонент CDO 1.2 x. При просмотре параметров настройки Office или Outlook компонент CDO отображается в разделе Параметры для Outlook.
Нужна дополнительная помощь?
Такой вариант через yandex.ru работает. А на внутренней почте появляется ошибка «Нет доступа к Интернет». Но там интернет и не нужен.
Кто знает, как поступить в этом случае?
Sub Send_Mail()
Const CDO_Cnf = «http://schemas.microsoft.com/cdo/configuration/»
Dim oCDOCnf As Object, oCDOMsg As Object
Dim SMTPserver As String, sUsername As String, sPass As String, sMsg As String
Dim sTo As String, sFrom As String, sSubject As String, sBody As String, sAttachment As String
On Error Resume Next
‘sFrom — как правило совпадает с sUsername
SMTPserver = [B10] ‘ SMTPServer: для Mail.ru «smtp.mail.ru»; для Яндекса «smtp.yandex.ru»; для Рамблера «mail.rambler.ru»
sUsername = [B11] ‘ Учетная запись на сервере
sPass = [B12] ‘ Пароль к почтовому аккаунту
If Len(SMTPserver) = 0 Then MsgBox «Не указан SMTP сервер», vbInformation, «www.Excel-VBA.ru»: Exit Sub
If Len(sUsername) = 0 Then MsgBox «Не указана учетная запись», vbInformation, «www.Excel-VBA.ru»: Exit Sub
If Len(sPass) = 0 Then MsgBox «Не указан пароль», vbInformation, «www.Excel-VBA.ru»: Exit Sub
sTo = [B2] ‘Кому
sFrom = [B3] ‘От кого
sSubject = [B4] ‘Тема письма
sBody = [B5] ‘Текст письма
‘sAttachment = [B6] ‘Вложение(полный путь к файлу)
sAttachment = Cells(6, «B»).Value
‘Проверка наличия файла по указанному пути
If Dir(sAttachment, vbDirectory) = «» Then sAttachment = «»
‘Назначаем конфигурацию CDO
Set oCDOCnf = CreateObject(«CDO.Configuration»)
With oCDOCnf.Fields
.Item(CDO_Cnf & «sendusing») = 2
.Item(CDO_Cnf & «smtpauthenticate») = 1
.Item(CDO_Cnf & «smtpserver») = SMTPserver
.Item(CDO_Cnf & «sendusername») = sUsername
.Item(CDO_Cnf & «sendpassword») = sPass
.Update
End With
‘Создаем сообщение
Set oCDOMsg = CreateObject(«CDO.Message»)
With oCDOMsg
Set .Configuration = oCDOCnf
.BodyPart.Charset = «koi8-r»
.From = sFrom
.To = sTo
.Subject = sSubject
.TextBody = sBody
‘.AddAttachment = sAttachment
If Len(sAttachment) > 0 Then .AddAttachment sAttachment
.Send
End With
Select Case Err.Number
Case -2147220973: sMsg = «Нет доступа к Интернет»
Case -2147220975: sMsg = «Отказ сервера SMTP»
Case 0: sMsg = «Письмо отправлено»
End Select
MsgBox sMsg, vbInformation, «Проверка доступа в Интернет»
Set oCDOMsg = Nothing: Set oCDOCnf = Nothing
End Sub
The CDO2000 class allows to send emails w/o user intervention using a SMTP server.
.
is included in Windows 2000 and later.
. The default is «us-ascii».
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 * CDO2000.prg #DEFINE cdoSendPassword "http://schemas.microsoft.com/cdo/configuration/sendpassword" #DEFINE cdoSendUserName "http://schemas.microsoft.com/cdo/configuration/sendusername" #DEFINE cdoSendUsingMethod "http://schemas.microsoft.com/cdo/configuration/sendusing" #DEFINE cdoSMTPAuthenticate "http://schemas.microsoft.com/cdo/configuration/smtpauthenticate" #DEFINE cdoSMTPConnectionTimeout "http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout" #DEFINE cdoSMTPServer "http://schemas.microsoft.com/cdo/configuration/smtpserver" #DEFINE cdoSMTPServerPort "http://schemas.microsoft.com/cdo/configuration/smtpserverport" #DEFINE cdoSMTPUseSSL "http://schemas.microsoft.com/cdo/configuration/smtpusessl" #DEFINE cdoURLGetLatestVersion "http://schemas.microsoft.com/cdo/configuration/urlgetlatestversion" #DEFINE cdoAnonymous 0 && Perform no authentication (anonymous) #DEFINE cdoBasic 1 && Use the basic (clear text) authentication mechanism. #DEFINE cdoSendUsingPort 2 && Send the message using the SMTP protocol over the network. #DEFINE cdoXMailer "urn:schemas:mailheader:x-mailer" DEFINE CLASS cdo2000 AS Custom PROTECTED aErrors[1], nErrorCount, oMsg, oCfg, cXMailer nErrorCount = 0 * Message attributes oMsg = Null cFrom = "" cReplyTo = "" cTo = "" cCC = "" cBCC = "" cAttachment = "" cSubject = "" cHtmlBody = "" cTextBody = "" cHtmlBodyUrl = "" cCharset = "" * Priority: Normal, High, Low or empty value (Default) cPriority = "" * Configuration object fields values oCfg = Null cServer = "" nServerPort = 25 * Use SSL connection lUseSSL = .F. nConnectionTimeout = 30 && Default 30 sec's nAuthenticate = cdoAnonymous cUserName = "" cPassword = "" * Do not use cache for cHtmlBodyUrl lURLGetLatestVersion = .T. * Optional. Creates your own X-MAILER field in the header cXMailer = "VFP CDO 2000 mailer Ver 1.1.100 2010" PROTECTED PROCEDURE Init This.ClearErrors() ENDPROC * Send message PROCEDURE Send IF This.GetErrorCount() > 0 RETURN This.GetErrorCount() ENDIF WITH This .ClearErrors() .oCfg = CREATEOBJECT("CDO.Configuration") .oMsg = CREATEOBJECT("CDO.Message") .oMsg.Configuration = This.oCfg ENDWITH * Fill message attributes LOCAL lnind, laList[1], loHeader, laDummy[1], lcMailHeader IF This.SetConfiguration() > 0 RETURN This.GetErrorCount() ENDIF IF EMPTY(This.cFrom) This.AddError("ERROR : From is empty.") ENDIF IF EMPTY(This.cSubject) This.AddError("ERROR : Subject is empty.") ENDIF IF EMPTY(This.cTo) AND EMPTY(This.cCC) AND EMPTY(This.cBCC) This.AddError("ERROR : To, CC and BCC are all empty.") ENDIF IF This.GetErrorCount() > 0 RETURN This.GetErrorCount() ENDIF This.SetHeader() WITH This.oMsg .From = This.cFrom .ReplyTo = This.cReplyTo .To = This.cTo .CC = This.cCC .BCC = This.cBCC .Subject = This.cSubject * Create HTML body from external HTML (file, URL) IF NOT EMPTY(This.cHtmlBodyUrl) .CreateMHTMLBody(This.cHtmlBodyUrl) ENDIF * Send HTML body. Creates TextBody as well IF NOT EMPTY(This.cHtmlBody) .HtmlBody = This.cHtmlBody ENDIF * Send Text body. Could be different from HtmlBody, if any IF NOT EMPTY(This.cTextBody) .TextBody = This.cTextBody ENDIF IF NOT EMPTY(This.cCharset) IF NOT EMPTY(.HtmlBody) .HtmlBodyPart.Charset = This.cCharset ENDIF IF NOT EMPTY(.TextBody) .TextBodyPart.Charset = This.cCharset ENDIF ENDIF * Process attachments IF NOT EMPTY(This.cAttachment) * Accepts comma or semicolon * VFP 7.0 and later *FOR lnind=1 TO ALINES(laList, This.cAttachment, [,], [;]) * VFP 6.0 and later compatible FOR lnind=1 TO ALINES(laList, CHRTRAN(This.cAttachment, [,;], CHR(13) + CHR(13))) lcAttachment = ALLTRIM(laList[lnind]) * Ignore empty values IF EMPTY(laList[lnind]) LOOP ENDIF * Make sure that attachment exists IF ADIR(laDummy, lcAttachment) = 0 This.AddError("ERROR: Attachment not Found - " + lcAttachment) ELSE * The full path is required. IF UPPER(lcAttachment) <> UPPER(FULLPATH(lcAttachment)) lcAttachment = FULLPATH(lcAttachment) ENDIF .AddAttachment(lcAttachment) ENDIF ENDFOR ENDIF IF NOT EMPTY(This.cCharset) .BodyPart.Charset = This.cCharset ENDIF * Priority IF NOT EMPTY(This.cPriority) lcMailHeader = "urn:schemas:mailheader:" .Fields(lcMailHeader + "Priority") = LOWER(This.cPriority) .Fields(lcMailHeader + "Importance") = LOWER(This.cPriority) DO CASE CASE This.cPriority = "High" .Fields(lcMailHeader + "X-Priority") = 1 && 5=Low, 3=Normal, 1=High CASE This.cPriority = "Normal" .Fields(lcMailHeader + "X-Priority") = 3 && 5=Low, 3=Normal, 1=High CASE This.cPriority = "Low" .Fields(lcMailHeader + "X-Priority") = 5 && 5=Low, 3=Normal, 1=High ENDCASE .Fields.Update() ENDIF ENDWITH IF This.GetErrorCount() > 0 RETURN This.GetErrorCount() ENDIF This.oMsg.Send() RETURN This.GetErrorCount() ENDPROC * Clear errors collection PROCEDURE ClearErrors() This.nErrorCount = 0 DIMENSION This.aErrors[1] This.aErrors[1] = Null RETURN This.nErrorCount ENDPROC * Return # of errors in the error collection PROCEDURE GetErrorCount RETURN This.nErrorCount ENDPROC * Return error by index PROCEDURE GetError LPARAMETERS tnErrorno IF tnErrorno <= This.GetErrorCount() RETURN This.aErrors[tnErrorno] ELSE RETURN Null ENDIF ENDPROC * Populate configuration object PROTECTED PROCEDURE SetConfiguration * Validate supplied configuration values IF EMPTY(This.cServer) This.AddError("ERROR: SMTP Server isn't specified.") ENDIF IF NOT INLIST(This.nAuthenticate, cdoAnonymous, cdoBasic) This.AddError("ERROR: Invalid Authentication protocol ") ENDIF IF This.nAuthenticate = cdoBasic ; AND (EMPTY(This.cUserName) OR EMPTY(This.cPassword)) This.AddError("ERROR: User name/Password is required for basic authentication") ENDIF IF This.GetErrorCount() > 0 RETURN This.GetErrorCount() ENDIF WITH This.oCfg.Fields * Send using SMTP server .Item(cdoSendUsingMethod) = cdoSendUsingPort .Item(cdoSMTPServer) = This.cServer .Item(cdoSMTPServerPort) = This.nServerPort .Item(cdoSMTPConnectionTimeout) = This.nConnectionTimeout .Item(cdoSMTPAuthenticate) = This.nAuthenticate IF This.nAuthenticate = cdoBasic .Item(cdoSendUserName) = This.cUserName .Item(cdoSendPassword) = This.cPassword ENDIF .Item(cdoURLGetLatestVersion) = This.lURLGetLatestVersion .Item(cdoSMTPUseSSL) = This.lUseSSL .Update() ENDWITH RETURN This.GetErrorCount() ENDPROC *---------------------------------------------------- * Add message to the error collection PROTECTED PROCEDURE AddError LPARAMETERS tcErrorMsg This.nErrorCount = This.nErrorCount + 1 DIMENSION This.aErrors[This.nErrorCount] This.aErrors[This.nErrorCount] = tcErrorMsg RETURN This.nErrorCount ENDPROC *---------------------------------------------------- * Format an error message and add to the error collection PROTECTED PROCEDURE AddOneError LPARAMETERS tcPrefix, tnError, tcMethod, tnLine LOCAL lcErrorMsg, laList[1] IF INLIST(tnError, 1427,1429) AERROR(laList) lcErrorMsg = TRANSFORM(laList[7], "@0") + " " + laList[3] ELSE lcErrorMsg = MESSAGE() ENDIF This.AddError(tcPrefix + ":" + TRANSFORM(tnError) + " # " + ; tcMethod + " # " + TRANSFORM(tnLine) + " # " + lcErrorMsg) RETURN This.nErrorCount ENDPROC *---------------------------------------------------- * Simple Error handler. Adds VFP error to the objects error collection PROTECTED PROCEDURE Error LPARAMETERS tnError, tcMethod, tnLine This.AddOneError("ERROR: ", tnError, tcMethod, tnLine ) RETURN This.nErrorCount ENDPROC *------------------------------------------------------- * Set mail header fields, if necessary. For now sets X-MAILER, if specified PROTECTED PROCEDURE SetHeader LOCAL loHeader IF NOT EMPTY(This.cXMailer) loHeader = This.oMsg.Fields WITH loHeader .Item(cdoXMailer) = This.cXMailer .Update() ENDWITH ENDIF ENDPROC *---------------------------------------------------- * PROTECTED PROCEDURE cPriority_assign(tvVal) * Check for incorrect values IF INLIST("~" + PROPER(tvVal) + "~", "~High~", "~Normal~", "~Low~") OR EMPTY(tvVal) This.cPriority = PROPER(ALLTRIM(tvVal)) ELSE This.AddError("ERROR: Invalid value for cPriority property.") ENDIF ENDPROC ENDDEFINE
I just got an email whose X-Mailer is «X-Mailer: Microsoft CDO for Windows 2000». It has as an attachment a .sgn file, whose content is an XML with one field apparently being a base64-encoded PDF:
<DocumentEnvelope><SignaturePackage><Signature =
xmlns=3D"http://www.w3.org/2000/09/xmldsig#"><SignedInfo><Canonicalizatio=
nMethod Algorithm=3D"http://www.w3.org/TR/2001/REC-xml-c14n-20010315" =
/><SignatureMethod =
Algorithm=3D"http://www.w3.org/2000/09/xmldsig#rsa-sha1" /><Reference =
URI=3D"#SignedDoc"><DigestMethod =
Algorithm=3D"http://www.w3.org/2000/09/xmldsig#sha1" =
/><DigestValue>MFV2XJ9rfjhGCyA948wKB741ChQ=3D</DigestValue></Reference></=
SignedInfo><SignatureValue>aKHfEGfu2p9RdShv1Vv/kqC6gjdymojq0rQA+AU/hPocrr=
VqMQk2wbbJD60jc8QPP0kPIo4vWqB1mVx5Y45HK0LFWxMDkJ2/CN8GcODEum2Mamn3W2j9tKV=
8JfJAexlW47LprDq99W9YwfpXusaEplCOErCRj/2dhnGc4SgZXxw=3D</SignatureValue><=
KeyInfo><KeyValue><RSAKeyValue><Modulus>nz78eiuYN1Jmm5ND8xLLbJ9QTrBpjTMfv=
h4mbmHbBSB7HSHU+7Izp5GCiyDAlmXa3JjqKBRjw2+OpwhsJf+KHPltKFKwOltTN9QJWS4HJm=
H1xqF4VAuwvpp1tlJd1KP5WL/j9YCYigzEfZIAAUC2KiFlAxoR1mwz3alMR4v96h8=3D</Mod=
ulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo><Object =
Id=3D"SignedDoc"><DocumentOriginName =
xmlns=3D"">ecd20f25-95b3-4dc3-b8e6-fc62d23db259</DocumentOriginName><Docu=
mentExtension xmlns=3D"">pdf</DocumentExtension><DocumentCreationDate =
xmlns=3D"">2014-02-27T22:10:27.4320656+02:00</DocumentCreationDate><Docum=
entContent =
xmlns=3D"">JVBERi0xLjQNJeLjz9MNCjMgMCBvYmoNPDwvQ291bnQgMS9LaWRzWzQgMCBSXS=
9QYXJlbnQgMiAwIFIgDS9UeXBlL1BhZ2VzPj4NZW5kb2JqDTQgMCBvYmoNPDwvQXJ0Qm94WzA=
(… etc. etc. …)
P9fdsc3jL4yg7at7G488BKcqQbpnZDkhXFsfhc/VIuPexfElgnf2oagaf/QjiZHy+ganiZcAH=
dFFFrN6xYK5n0JL5g330NKzD5CHBS8X1civ8VUAKdWjgI8pm1rFsm4v20SwIp/81OH1w=3D=3D=
</CertBase64></Certificate></SignaturePackage></DocumentEnvelope>
If I copy out just the DocumentContent part, and base64-decode it, I see a PDF 1.3 header, but some decoders choke on it, and anyway, I can’t get a working PDF from that thing. So:
- How can I manually extract the PDF file from there?
- Is there a standalone tool for extracting files from such mail messages, or from .sgn files?
- Is there a Thunderbird extension which handles these, and presents the PDF as a regular attachment?
Notes:
- The file was sent automatically by the Israel courts’ ‘Net Ha-Mishpat’ platform. I can contact the courts but they have no technically-literate people, and I can’t contact the software contractor they used.
- I know of people who have, in the past, managed to extract decoded files from these .sgn’s, I just don’t know how exactly.
asked Feb 27, 2014 at 21:13
einpoklumeinpoklum
8,07318 gold badges72 silver badges138 bronze badges
I got one of those documents myself today.
Since explaining what is wrong to the tech support people seemed likely to take more time than attempting to extract it myself, I created a small python script to extract and decode the pdf document that was embedded in the sig file.
That is, assuming that there is a single attached pdf file and the sig file format is the same as mine.
I hope that someone would find it useful.
import base64
import xml.etree.ElementTree as ET
import sys
def decode(infile, outfile):
tree = ET.parse(infile)
xmlns = '{http://www.w3.org/2000/09/xmldsig#}'
b64 = tree.find("./SignaturePackage/{0}Signature/{0}Object/DocumentContent".format(xmlns)).text
txt = base64.b64decode(b64)
with open(outfile, 'bw+') as f:
f.write(txt)
if __name__ == "__main__":
if len(sys.argv) < 2:
print('usage: python unpack.py <input_filename>')
exit(1)
infile = sys.argv[1]
outfile = 'out.pdf'
decode(infile, outfile)
print('Done. Result saved to {0}'.format(outfile))
I created a gist for this script.
You need to have python 3.x installed, put the sig file and the python script in the same folder (or provide the file path to the script) and execute it like so:
python unpack.py <sig_filename>
This will create a file named out.pdf in the same folder.
answered May 12, 2015 at 10:20
5
Here’s a rudimentary script you can use on Unix-like systems (and probably on Windows too with a little modification) to extract the PDF file out of the document envelope; I call it sgn2pdf
(since the doc envelope file have an sgn extension). Its command-line interface is
sgn2pdf [INPUT_FILENAME] [OUTPUT_FILENAME]
i.e. if you add a first argument it will read from that file rather than from the standard input; and if you add a second argument it will redirect the output into the second file specified.
Source:
#!/bin/bash
#
# Extract a PDF file from an Israeli courts' .sgn PDF document envelope
exec 3<&0 # tie (new) file descriptor 3 to what is currently the standard input
exec 4>&1 # tie (new) file descriptor 4 to what is currently the standard output
if [[ $# > 0 ]]; then
exec 3<$1
shift
fi
if [[ $# > 0 ]]; then
exec 4>$1
shift
fi
exec <&3 >&4
sed -r 's/^.*<DocumentContent[^>]*>//; s/</Document.*$//;' | base64 -d -i >&4
The base64
decoder is part of the GNU coreutils
package and should be available on any Linux distribution.
answered Oct 30, 2016 at 8:10
einpoklumeinpoklum
8,07318 gold badges72 silver badges138 bronze badges
The use of CDO 200 and the document envelope indicate that the email was likely sent automatically or programmatically, i.e. via a script, out of Access, or in some other way via SMTP and a CDO-compliant program (not a normal mail client).
The SGN file is unlikely to be a true SGN file, which is a «Sierra Print Artist» file; it seems more likely that someone has used the extension manually for a signature file.
I do not believe that this file was intended to be the sort of attachment that you would be expected to open. It seems far more likely that the file you’re seeing is included with the email as a way for the sender to show it as «signed» when it is automatically generated. Because the PDF is embedded within the XML file, there is likely no extension which would automatically decode the section of the attachment that you believe to be a PDF. You could try copying the entire section and then decoding it, and saving the decoded text with a unicode-compliant text editor, then see if that opens as a readable PDF.
But I think you are wasting your time and this attachment is along the lines of what you’d see if someone included a vCard which contained an image when they sent you email out of some program via CDO. That is, it’s not intended to be decoded, because if you could do that, then perhaps you could falsify the signature of the sender.
Have you tried contacting the sender to find out whether the attachment has any meaning? It seems fairly obvious to me that it is just intended to be a qualifying signature file. The header tells you that the algorithm used to generate the signature is at
http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd#rsa-sha1 — that alone should tell you that it’s not a file that you are meant to open as such.
answered Feb 28, 2014 at 6:08
DebraDebra
4,2501 gold badge17 silver badges24 bronze badges
3
Probably too late, but if you got this file from the Israeli court system (נט המשפט), then here they give a link (this link) to a windows program that opens it.
answered Nov 29, 2015 at 22:49
yohbsyohbs
1011 bronze badge
2
Создаю письмо через CDO.Message. Отсылаю его сам себе.
Значимые куски скрипта:
Письмо успешно уходит, мне приходит уведомление о доставке письма, но не приходит уведомление о прочтении. Заголовок письма формируется следующий:
Received: from KEMIT03 (KEM-ITxx [10.xx.xx.12]) by exchange.kemerovo.goracadem.ru with SMTP (Microsoft Exchange Internet Mail Service Version 5.5.2653.13)
id LTWFHF5V; Thu, 26 May 2005 10:31:42 +0700
Return-Receipt-To: <koltsov@kemerovo.goracadem.ru>
From: <koltsov@kemerovo.goracadem.ru>
To: <koltsov@kemerovo.goracadem.ru>
Subject: This is a CDO test message
Date: Thu, 26 May 2005 10:29:38 +0800
Message-ID: <000001c5619a$c3761200$0c1e140a@KEMIT03>
MIME-Version: 1.0
Content-Type: text/plain;
charset=»koi8-r»
Content-Transfer-Encoding: 7bit
X-Mailer: Microsoft CDO for Windows 2000
Disposition-Notification-To: <koltsov@kemerovo.goracadem.ru>
Thread-Index: AcVhmsNxa14gLdRhTbGiPWJZ/qqZZg==
Content-Class: urn:content-classes:message
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1409
Формирую письмо через MS Outlook (так же самому себе). Успешно приходят оба уведомления: и о доставке письма и о прочтении. Заголовок письма Outlook формирует вот такой:
Значимых различий в заголовках я не вижу в упор.
Причем в свойствах письма(смотрю их в Outlook: Файл-Свойства), сформированного Outlook, указано следующее:
Требуется уведомление о прочтении: Да
Требуется уведомление о доставке: Да
Свойства же письма, сформированнго скриптом, показываются вот такие:
Требуется уведомление о прочтении: Нет
Требуется уведомление о доставке: Да
Два взаимосвязанных вопроса.
Первый: как же мне скриптом формировать письмо, чтобы приходило еще и уведомление о прочтении.
Второй: что такого знает Outlook, чего не знаю я? То есть по каким признакам он определяет, что в «его» письме все уведомления включены, а в «скриптовом» уведомление о прочтении не включено?