Yesterday, I was really unhappy with my computer. The programming at hand was clear and seemed to be a straightforward deal. In the end, it was not so easy.
The Deal: A client machine (workstation, Win98, 2000, or ME) will actively send emails from within a custom VB6 application (exe). Additionally, the application instantiated a custom local object (dll) that contained a public SendMail function with parameters to send the mail.
NOTE: I found some software that makes development a lot faster and improves windows in general: Firefox with Google Toolbar
I stepped through this process by first (my machine is an NT workstation with transaction server):
1. Creating a VB form in MS Visual Basic 6 to hold the Click event and Public SendMail function
2. Transfer the Public SendMail function to a class object
3. Compile and run, calling the function from the class
So easy (I thought!). I created a button to fire my SendMail function in the form (form1). I did not think that CDONTS is a server library and not available on other client types!
Private Sub Command1_Click()
Call blnSendMail ("
burnettm@hotmail.com", "
burnettm@hotmail.com", "mail", "functional")
End Sub
Private Function blnSendMail(strTo As String, strFrom As String, strSubject As String, strBody As String) As Boolean
'The CDO object is located on NT server, usually with the resource kit installed, ADCSRV4 is properly configured.
On Error Resume Next
Dim mail As CDONTS.NewMail
Set mail = New CDONTS.NewMail
mail.To = strTo
mail.From = strFrom
mail.Subject = strSubject
mail.Body = strBody
mail.Send
Set mail = Nothing
If Err.Number <> 0 Then
blnSendMail = False
Else
blnSendMail = True
End If
End Function
Ok, so this script failed miserably when run on my workstation, but ran successfully on a server. However, this was not what I needed and I turned to MAPI. Now, MAPI is like an extended CDO object and is about having a ‘Profile’ setup in the "Inbox" on your computer. My next attempt, below, called a MAPI object in a VB form using an Inbox profile.
First, you must have an Inbox profile (obviously). This profile points to the remote Exchange Server you wish to use. On the screen, ‘right click’ on ‘INBOX’ and select properties. If no Profile exists you will be prompted to create one, do it. The next screen will have check boxes, select the exchange server and move on to Profile name. Enter the Profile name. Follow the directions on the next screen to complete the setup. If you already have a profile, if will be displayed in the upper left corner or ‘click’ ‘show profile’ to see the profile name.
Next, we must add the MAPI controls to our VB form. Click on PROJECTS / COMPONENTS / BROWSE and locate the MAPI ocx in "../systerm32/msmapi32.ocx". ADD the control to the form.
Our new Function to send mail with MAPI looks like this (profile name = Matt):
Call MapiClass.blnSendMail("
burnettm@hotmail.com", "
burnettmFROM@hotmail.com", "mail", "MAPI mail is functional", "Matt")
Public Function blnSendMail (strTo As String, strFrom As String, strSubject As String, _
strBody As String, pName As String) As Boolean
Dim MAPISession3 As MAPISession
Set MAPISession3 = MAPISession1
With MAPISession3
.DownLoadMail = False
.LogonUI = True
.UserName = "Matt" 'This is the Profile Name in the InBox
.Password = ""
If MAPIMessages1.SessionID = 0 Then .SignOn
.NewSession = True
MAPIMessages1.SessionID = .SessionID
End With
Dim MAPIMessages3 As MAPIMessages
Set MAPIMessages3 = MAPIMessages1
With MAPIMessages3
.Compose
.RecipAddress = strTo
.AddressResolveUI = True
.ResolveName
.MsgSubject = strSubject
.MsgNoteText = strBody
.Send False
End With
Set MAPIMessages3 = Nothing
Set MAPISession3 = Nothing
If Err.Number <> 0 Then
blnSendMail2 = False
Else
blnSendMail2 = True
End If
End Function
I ran this function within the VB form and it worked great!
Step 2 of my plan was to insert the function into a class. The class function had exactly the same code base as the form function. I ran the program with the following call:
Call MapiClass.blnSendMail("
burnettm@hotmail.com", "
burnettm@hotmail.com", _
"MAPI mail", "MAPI mail is functional", "Matt")
The program failed!!! The "Set MAPISession3 = MAPISession1" produced a type error. There are some examples of how to compile a form in a dll, then reference ActiveX controls from the form. However, a "form" is explicitly a UI and does not belong in a dll (IMO). This issue is related to the fact that ActiveX controls require a valid "Control Container", which a "class object" is not. To solve this problem, VB6 allows ‘late binding’ to OCX controls for use. This fact is significant in and by itself!
To late bind the MAPI ActiveX control:
Set objSession = CreateObject("MAPI.SESSION")
Additionally, you can late bind the CDO control for use in a class object:
Set mail = CreateObject("CDONTS.NewMail.1")
Having the MAPI object created successfully, I put the previous code in place and ran the program. Again, the program failed. Creating the object within the class exposes a different set of properties and methods. The following code allows the creation of a MAPI object and sends the mail. NOTE: the difference in properties between the VB form OCX and the late bound object.
Call MapiClass.blnSendMail("
burnettm@hotmail.com", "
burnettm@hotmail.com", "MAPI mail", "MAPI mail is functional", "Matt")
Public Function blnSendMail (strTo As String, strFrom As String, strSubject As String, _
strBody As String, pName As String) As Boolean
On Error Resume Next
Dim objSession As Object 'MAPI.Session
Dim objMessage As Object 'MAPI.Message
Dim objRecip As Object 'MAPI.Recipient
Set objSession = CreateObject("MAPI.SESSION")
objSession.Logon ProfileName:=pName, showDialog:=False
Set objMessage = objSession.Outbox.Messages.Add
objMessage.Subject = strSubject
objMessage.Text = strBody
Set objRecip = objMessage.Recipients.Add
objRecip.Name = strTo
objRecip.Type = 1 ' 1 is the value of the "mapiTo" constant.
objRecip.Resolve
objMessage.Update
objMessage.Send showDialog:=False
objSession.Logoff
If Err.Number <> 0 Then
blnSendMail = False
Else
blnSendMail = True
End If
End Function
This class function will send email using the remote Exchange server referred to in the Inbox profile.
The final class function took the shape of CDO and MAPI. The reason is that our dlls our built and tested on workstations but ultimately run on a server. MAPI was implemented to allow for testing on workstation. However, when the class is on a server there is no reason to load such a heavy class (MAPI) when CDO will do the job. Additionally, CDO does not require the Inbox profile setup.
Public Function blnSendMail(strTo As String, strFrom As String, strSubject As String, _
strBody As String, pName As String) As Boolean
'The CDO object is located on NT server, usually with the resource kit installed.
On Error Resume Next
Dim mail As Object
Set mail = CreateObject("CDONTS.NewMail.1")
mail.To = strTo
mail.From = strFrom
mail.Subject = strSubject
mail.Body = strBody
mail.Send
Set mail = Nothing
If (Err.Number = 0) Then
blnSendMail77 = True
Exit Function
Else
Err.Clear
'This script requires that a profile is setup in the local computer's INBOX properties
'Uses the profile info for return information.
Dim objSession As Object 'MAPI.Session
Dim objMessage As Object 'MAPI.Message
Dim objRecip As Object 'MAPI.Recipient
Set objSession = CreateObject("MAPI.SESSION")
objSession.Logon ProfileName:=pName, showDialog:=False
Set objMessage = objSession.Outbox.Messages.Add
objMessage.Subject = strSubject
objMessage.Text = strBody
Set objRecip = objMessage.Recipients.Add
objRecip.Name = strTo
objRecip.Type = 1 ' 1 is the value of the "mapiTo" constant.
objRecip.Resolve
objMessage.Update
objMessage.Send showDialog:=False
objSession.Logoff
If Err.Number <> 0 Then
blnSendMail77 = False
Else
blnSendMail77 = True
End If
End If
End Function
Additional notes and research:
Calling the Logon Method of MAPI object with server and account:
strProfileInfo = "ADCSRV1" & vbLf & "
mburnett@adctech.com"
objSession.Logon "", "", False, True, 0, True, strProfileInfo
You will find some permission issues with exchange server: Refer to MS Q195681 "Configure an Exchange Mailbox for Anonymous Access", to get started.
The Logon Method of the MAPI object also has an anonymous profile string"
'strProfileInfo = "/o=" + strEnterprise + "/ou=" + strSite + "/cn=Configuration/cn=Servers/cn=" + strServer + vbLf + "anon" + vbLf + "anon"
'strProfileInfo = "/o=1ADCTECH/ou=1ADCTECH/cn=Configuration/cn=Servers/cn=ADCSRV1" & vbLf & "anon" & vbLf & "anon"
Article By, Matthew P. Burnett.