SMTP EnvelopeFields Code Example

SMTP EnvelopeFields Code Example

The following code example can be used only with Simple Mail Transfer Protocol (SMTP) OnArrival event sinks. The IMessage.EnvelopeFields property returns an empty collection in all cases except for a Message object reference passed to a sink during a transport event.

For the purposes of illustration, the example code performs the following tasks:

  1. Checks the subject of the message. If the subject is equal to ---BAD MESSAGE---, it sets the messagestatus field to cdoStatAbortDelivery to block delivery. It also sets the EventStatus parameter (in the OnArrival event sink) to the event call equal to cdoSkipRemainingSinks, so that the event dispatcher does not notify remaining sinks of the message’s arrival.
  2. If the recipientlist envelope field is equal to distributionlist@example.com, the recipientlist field is expanded (replaced) with a hypothetical list, namely example@example.com and example2@example.com.
  3. Writes a log file entry to disk that contains the envelope fields for the message, after the dynamic-link library (DLL) has expanded, along with the message stream, which is retrieved using IMessage.GetStream. This is to allow inspection of the fields and the message stream after the message is sent and to verify that everything is working correctly.

Example

Implements IEventIsCacheable
Implements ISMTPOnArrival

Private Sub IEventIsCacheable_IsCacheable()
  ' just return S_OK which means do nothing!
  ' Object will be cached for subsequent use
End Sub

Sub ISMTPOnArrival_OnArrival(ByVal iMsg as CDO.Message, EventStatus as CdoEventStatus)
  Dim RecipListFld as ADODB.Field
  Dim Fld as ADODB.Field
  Dim Flds as ADODB.Fields
  Dim strOutPut as String
  Set Flds = iMsg.EnvelopeFields

  if iMsg.Subject = "---BAD MESSAGE---" Then    Flds("https://schemas.microsoft.com/cdo/smtpenvelope/messagestatus") = cdoStatAbortDelivery
    Flds.Update ' must call update to commit changes to fields
    EventStatus = cdoSkipRemainingSinks
    strOutPut = "Aborted delivery of this message:" & vbCrLf
    strOutPut = strOutPut & "Envelope Fields: " & vbCrLf
    For Each Fld in Flds
      strOutPut = strOutPut & "------" & vbCrLf
      strOutPut = strOutPut & "Name: " & Fld.Name & vbCrLf
      strOutPut = strOutPut & "Value: " & Fld.Value & vbCrLf
    Next Fld
    strOutPut = "Message was: " & vbCrL
    Dim Strm as ADODB.Stream
    Set Strm = iMsg.GetStream
    strOutPut = strOutPut & Strm.ReadText & vbCrLf & vbCrLf
  Else
    Dim strRecipList as String
    Set RecipListFld = Flds("https://schemas.microsoft.com/cdo/smtpenvelope/recipientlist")

    strRecipList = RecipListFld.Value
    If strRecipList = "distributionlist@example.com" Then
      ' Do DL expansion here
      strRecipList = "SMTP:example@example.com;SMTP:example2@example.com;"
      RecipListFld.Value = strRecipList
      Flds.Update ' must call update to commit changes to fields
      strOutPut = "Expanded DL distributionlist@example.com" & vbCLf
      strOutPut = "Envelope Fields: " & vbCrLf
      For Each Fld in Flds
        strOutPut = strOutPut & "------" & vbCrLf
        strOutPut = strOutPut & "Name: " & Fld.Name & vbCrLf
        strOutPut = strOutPut & "Value: " & Fld.Value & vbCrLf
      Next Fld
      strOutPut = "Message was: " & vbCrLf
      Dim Strm as ADODB.Stream
      Set Strm = iMsg.GetStream
      strOutPut = strOutPut & Strm.ReadText & vbCrLf & vbCrLf
    End If
  End If

  Dim FS as New Scripting.FileSystemObject
  Dim File as Scripting.TextStream
  Set File = FS.CreateTextFile("c:\envelopefieldlog\fields.log",True,False)
  File.Write strOutPut
End Sub
#include "resource.h"       // main symbols
#import <msado15.dll> no_namespace raw_interfaces_only
#import <cdosys.dll> no_namespace raw_interfaces_only
#import <seo.dll> no_namespace raw_interfaces_only

/////////////////////////////////////////////////////////////////////////////
// CSink1
class ATL_NO_VTABLE CSink1 :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CSink1, &CLSID_Sink1>,
public IDispatchImpl<ISMTPOnArrival, &__uuidof(ISMTPOnArrival), &LIBID_TRANSSINKEXLib>
{
public:
CSink1()
{
}

DECLARE_REGISTRY_RESOURCEID(IDR_SINK1)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CSink1)
   COM_INTERFACE_ENTRY(ISMTPOnArrival)
   COM_INTERFACE_ENTRY(IEventIsCacheable)
   COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

// ISink1
public:
STDMETHOD(IsCacheable)() { return S_OK;}
STDMETHOD(OnArrival)(IMessage* pMsg,CdoEventStatus* pStat);

};

// these are in cdosysstr.h and cdoexstr.h
const BSTR cdoRecipientList  = L"https://schemas.microsoft.com/cdo/smtpenvelope/recipientlist";
const BSTR cdoMessageStatus  =L"https://schemas.microsoft.com/cdo/smtpenvelope/messagestatus";

HRESULT CSink1::OnArrival(IMessage* pMsg,CdoEventStatus* pStat) {

  CComPtr<Field> pField;
  CComPtr<Fields> pFields;
  CComPtr<Field> pDL;

  HRESULT hr = pMsg->get_EnvelopeFields(&pFields);
  CComBSTR bstrSubject;
  hr = pMsg->get_Subject(&bstrSubject);

  CComBSTR bstrOutPut = "This is a start of an entry here \r\n";
  //
  // check the subject for ---BAD MESSAGE---
  // note that this is for illustration only ;-)
  // if we have ---BAD MESSAGE---,
  //   *  set the pStat arg to CdoSkipRemainingSinks
  //   *  set the messagestatus field to cdoStatAbortDeliver
  //   *  write the log entry
  //
  if(bstrSubject == CComBSTR("---BAD MESSAGE---")){
    *pStat = cdoSkipRemainingSinks;
    CComPtr<Field> pFldMsgStatus;
    pFields->get_Item(CComVariant(CComBSTR(cdoMessageStatus)),&pFldMsgStatus);
    pFldMsgStatus->put_Value(CComVariant((long)cdoStatAbortDelivery));
    hr = pFields->Update();
    if(FAILED(hr))
      return hr;
    //assert(SUCCEEDED(hr));
    bstrOutPut += " got a ---BAD MESSAGE--- here: \r\n";
    CComPtr<_Stream> pStrm;
    hr = pMsg->GetStream(&pStrm);
    if(FAILED(hr))
      return hr;
    CComBSTR bstrStreamData;
    hr = pStrm->ReadText(-1,&bstrStreamData);
    if(FAILED(hr))
      return hr;
    bstrOutPut += bstrStreamData;
  }
  // check for the address SMTP:distributionlist@example.com
  // if this is the recipient list,
  //   *  replace with
  // "SMTP:example@example.com;SMTP:example2@example.com;"
  //   * write log file
  //
  else {
    hr = pFields->get_Item(CComVariant(cdoRecipientList),&pField);
    CComVariant varRecipName;
    hr = pField->get_Value(&varRecipName);
    if(FAILED(hr)) {
      bstrOutPut += "error getting value for recipientlist\r\n";
      goto writelog;
    }
    CComBSTR name = varRecipName.bstrVal;
    if(name == CComBSTR("SMTP:distributionlist@example.com;")) {
      hr = S_OK;
      CComVariant varDL = "SMTP:example@example.com;SMTP:example2@example.com;";
      hr = pField->put_Value(varDL);
      if(FAILED(hr)) {
         bstrOutPut += "error putting recpientlist value\r\nhr= ";
         bstrOutPut.Append(CComBSTR(hr));
         bstrOutPut += "\r\n";
         goto writelog;
      }
      hr = pFields->Update();
      bstrOutPut += "Updated distlist: \r\n";
      CComPtr<_Stream> pStrm;
      hr = pMsg->GetStream(&pStrm);
      if(FAILED(hr))
        return hr;
      CComBSTR bstrStreamData;
      hr = pStrm->ReadText(-1,&bstrStreamData);
      if(FAILED(hr))
        return hr;
      bstrOutPut += bstrStreamData;
    }
  }


writelog:


    LPCWSTR szFilename = L"c:\\logs\\events.txt";
    HANDLE hFile;
    int nBufSize = 0;
    ULONG nSizeWritten = 0 ;
    BOOL fRC = FALSE;

    hFile=CreateFileW(szFilename,
                      GENERIC_WRITE,
                      FILE_SHARE_READ|FILE_SHARE_WRITE| FILE_SHARE_DELETE,
                      NULL,
                      OPEN_ALWAYS,
                      FILE_ATTRIBUTE_NORMAL,
                      NULL);
    if(hFile == INVALID_HANDLE_VALUE)
        return E_POINTER;

  SetFilePointer(hFile,0,NULL,FILE_END);
  nBufSize = lstrlenW(bstrOutPut);
  fRC = WriteFile(hFile,bstrOutPut,nBufSize * 2,&nSizeWritten,NULL);
  if(fRC == FALSE)
        return S_FALSE;
  CloseHandle(hFile);

  return S_OK;
}