3/29/10

VBScript To Send Email Using CDO

Sending email with CDO is a simple task. First we create a reference to the CDO component


Set objMessage = CreateObject("CDO.Message")
then fill-in Sender, Subject and Recipient (To) fields of the headers and the body text which can be either plain text or HTML. You can also add a file attachment. You then use the Send method to send the email.

Below I'll show all three types of emails, and how to send an email using a remote SMTP server in the event you are not running your own. I've added and example to illustrate how to request a return receipt and delivery status notifications.

Please note, when using the AddAttachment method in your scripts you must use a fully qualified pathname as the argument to the method. Using just a file name or a relative path will produce the error The specified protocol is unknown.

If you receive an error message related to objMessage.From then you should try replacing it with objMessage.Sender

I've added sample code to illustrate how to load the body of the email from a text file on your disk.

I've added a sample of how to load recipient data from a database.

I've added a sample illustrating how to use data from Excel in an email.

If you are looking for an ASP based email form processor then please look here.

If you are interested in a mass mailer using CDO and VBScript, look here.


This sample sends a simple text email that can be viewed in any email client.

Set objMessage = CreateObject("CDO.Message")
objMessage.Subject = "Example CDO Message"
objMessage.From = "me@my.com"
objMessage.To = "test@paulsadowski.com"
objMessage.TextBody = "This is some sample message text."
objMessage.Send


Sending an HTML email.

Note the use of the Cc & Bcc properties to send using Blind Carbon Copy (Bcc) and Carbon Copy (Cc).
These properties can be used with either text or HTML email.

Set objMessage = CreateObject("CDO.Message")
objMessage.Subject = "Example CDO Message"
objMessage.From = "me@my.com"
objMessage.To = "test@paulsadowski.com"

'The line below shows how to send using HTML included directly in your script
objMessage.HTMLBody = "

This is some sample message html.

"

'The line below shows how to send a webpage from a remote site
'objMessage.CreateMHTMLBody "http://www.paulsadowski.com/wsh/"

'The line below shows how to send a webpage from a file on your machine
'objMessage.CreateMHTMLBody "file://c/temp/test.htm"

objMessage.Bcc = "you@your.com"
objMessage.Cc = "you2@your.com"
objMessage.Send


Sending a text email with an attached file.

By repeating the .AddAttachment method you can attach more than one file.
When attaching files keep in mind that your recipient may be limited in their
ability to receive files above a certain size. Many ISPs limit emails to 8 or 10MB each.
You should not send large files to anyone before obtaining their permission.

Set objMessage = CreateObject("CDO.Message")
objMessage.Subject = "Example CDO Message"
objMessage.From = "me@my.com"
objMessage.To = "test@paulsadowski.com"
objMessage.TextBody = "This is some sample message text."
objMessage.AddAttachment "c:\temp\readme.txt"
objMessage.Send


Sending a text email using a remote server.

Sometimes you need to send email using another server. It may be required by your
company, or your ISP may be blocking the SMTP port, or your dynamic IP may be
blacklisted for being in a dynamic pool.

This code shows you how to use a remotes server rather than the SMTP server
on your own machine.

Set objMessage = CreateObject("CDO.Message")
objMessage.Subject = "Example CDO Message"
objMessage.From = "me@my.com"
objMessage.To = "test@paulsadowski.com"
objMessage.TextBody = "This is some sample message text."

'==This section provides the configuration information for the remote SMTP server.
'==Normally you will only change the server name or IP.

objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2

'Name or IP of Remote SMTP Server
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtp.myserver.com"

'Server port (typically 25)
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25

objMessage.Configuration.Fields.Update

'==End remote SMTP server configuration section==

objMessage.Send


Sending a text email using authentication against a remote SMTP server.

More and more administrators are restricting access to their servers to control spam or limit
which users may utilize the server. This example shows you how to use basic authentication,
the most commonly used authentication method, when the SMTP server you are using requires it.

This code is slightly more complex but not very difficult to understand or work with.

Const cdoSendUsingPickup = 1 'Send message using the local SMTP service pickup directory.
Const cdoSendUsingPort = 2 'Send the message using the network (SMTP over the network).

Const cdoAnonymous = 0 'Do not authenticate
Const cdoBasic = 1 'basic (clear-text) authentication
Const cdoNTLM = 2 'NTLM

Set objMessage = CreateObject("CDO.Message")
objMessage.Subject = "Example CDO Message"
objMessage.From = """Me"" "
objMessage.To = "test@paulsadowski.com"
objMessage.TextBody = "This is some sample message text.." & vbCRLF & "It was sent using SMTP authentication."

'==This section provides the configuration information for the remote SMTP server.

objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2

'Name or IP of Remote SMTP Server
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mail.your.com"

'Type of authentication, NONE, Basic (Base64 encoded), NTLM
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = cdoBasic

'Your UserID on the SMTP server
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusername") = "youruserid"

'Your password on the SMTP server
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "yourpassword"

'Server port (typically 25)
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25

'Use SSL for the connection (False or True)
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = False

'Connection Timeout in seconds (the maximum time CDO will try to establish a connection to the SMTP server)
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 60

objMessage.Configuration.Fields.Update

'==End remote SMTP server configuration section==

objMessage.Send


Send using authentication against a remote server with a file attachment and return receipt and
delivery disposition notification requests. In order to use the Delivery Status Notifications (Return
Receipt and Delivery Disposition requests) we need to create a reference to the CDO Configuration
object in addition to the CDO Message object and set a small number of properties. You must
use cdoSendUsingPort (network connection) and not the SMTP server's pickup directory
(cdoSendUsingPickup).

Const cdoSendUsingPickup = 1
Const cdoSendUsingPort = 2 'Must use this to use Delivery Notification
Const cdoAnonymous = 0
Const cdoBasic = 1 ' clear text
Const cdoNTLM = 2 'NTLM
'Delivery Status Notifications
Const cdoDSNDefault = 0 'None
Const cdoDSNNever = 1 'None
Const cdoDSNFailure = 2 'Failure
Const cdoDSNSuccess = 4 'Success
Const cdoDSNDelay = 8 'Delay
Const cdoDSNSuccessFailOrDelay = 14 'Success, failure or delay

set objMsg = CreateObject("CDO.Message")
set objConf = CreateObject("CDO.Configuration")

Set objFlds = objConf.Fields
With objFlds
.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = cdoSendUsingPort
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mail.yourhost.com"
.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = cdoBasic
.Item("http://schemas.microsoft.com/cdo/configuration/sendusername") = "your-username"
.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "your-password"
.Update
End With

strBody = "This is a sample message." & vbCRLF
strBody = strBody & "It was sent using CDO." & vbCRLF

With objMsg
Set .Configuration = objConf
.To = "test@paulsadowski.com"
.From = "me@my.com"
.Subject = "This is a CDO test message"
.TextBody = strBody
'use .HTMLBody to send HTML email.
.Addattachment "c:\temp\Scripty.zip"
.Fields("urn:schemas:mailheader:disposition-notification-to") = "me@my.com"
.Fields("urn:schemas:mailheader:return-receipt-to") = "me@my.com"
.DSNOptions = cdoDSNSuccessFailOrDelay
.Fields.update
.Send
End With


In real world usage you'll most likely want to load the text of the email from a file on your
computer. The sample code below shows you how to do this. The text can be either
plain text or HTML as needed.Our example assumes your text is in the file
C:\Temp\MyEmail.txt. This code loads the entire content of that file into a variable,
here named BodyText which you can then reference in your CDO code. We
assume BodyText is in the scope of your CDO code.

'These constants are defined to make the code more readable
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Dim fso, f
Set fso = CreateObject("Scripting.FileSystemObject")
'Open the file for reading
Set f = fso.OpenTextFile("c:\temp\MyEmail.txt", ForReading)
'The ReadAll method reads the entire file into the variable BodyText
BodyText = f.ReadAll
'Close the file
f.Close
Set f = Nothing
Set fso = Nothing

Once the text is loaded you can use it in your CDO code something like this...

objMessage.TextBody = BodyText
or
objMessage.HTMLBody = BodyText


Load Recipients from a Database

As is the case with most thing in Windows there are many ways to accomplish a task. This is one method of many.

Our database is an Access format database that resides on the local disk. The table in our database that we are interested in is called Customers and each record consists of 4 fields named "ID", "Name", "Email", and "Customer", where ID is an autogenerated index, Name is the full name of our customer, Email is the customer's email address and Customer is their customer identification number.

We are only interested here in two fields, Name and Email.

ID

Name

Email

Customer

1

Bob Jones

bjones@test.com

12345

2

Jane Smith

jsmith@test.net

12346

Set OBJdbConnection = CreateObject("ADODB.Connection")
OBJdbConnection.Open "DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=c:\Acme Inc\Databases\Customers.mdb"
SQLQuery = "SELECT Name, Email FROM Customers"
Set Result = OBJdbConnection.Execute(SQLQuery)
if Not Result.EOF then
Do While Not Result.EOF
SendMail Result("Name"), Result("Email")
Result.MoveNext
Loop
end if
OBJdbConnection.Close

As you can see the code is simple. We create a database connection object then open the database and query it for the Name and Email fields of each customer. Those values are passed for each customer to a subroutine that sends the customer an email.

Sub SendMail(TheName, TheAddress)
Dim objMessage, Rcpt

Rcpt = Chr(34) & TheName & Chr(34) & "<" & TheAddress & ">"
Set objMessage = CreateObject("CDO.Message")
objMessage.Subject = "This Month's Sales"
objMessage.From = """Acme Sales"" "
objMessage.To = Rcpt
objMessage.HTMLBody = TextBody
objMessage.Send

End Sub


If you are not accustomed to working with databases then this may have seemed a daunting task but as you can see from the code above, it's really quite simple.

We've already covered sending email so I'll just mention that this subroutine assumes the HTML body text is a variable called TextBody (see Loading email body text from a file)

Also we format the recipient's address in the standard format of "Name" for a more professional look to the recipient..

Remarks

As previously stated there are many ways to do this. I've presented one simple method here. Your own use may be with an ODBC connection; it may use mySQL or SQL Server; it may include personalization of the email body text and more. My intent here was to provide you with the basics to get you started.


Load data from an Excel Worksheet

There may be times when you want to generate an email using data from an application such as Excel. This is one simple illustration of how that could be done.

In our example we will be using a Workbook with three columns starting at column A row 1. Each row represents one product in our inventory and the three columns contains the following data about each item: Part Number, Name of Part, Number of Items in Inventory. Graphically our Workbook looks like this:

Part

Name

Stock

4583586

Fliggalhopper

452

5898547

Looplonger

293

This particular script works by walking down each cell of column 1 till it finds an empty cell which it assumes is the end of the list of entries. If your file may contain empty cells then you can use the Worksheet's UsedRange.Rows.Count property to find the last row in which an entry is made. Your code would then use a for loop something like this:

rowLast = objSheet.UsedRange.Rows.Count
for x = rowStart to rowLast
' do stuff
next

Function GetData()
Dim x, strTemp, objExcel, objWB

Set objExcel = Wscript.CreateObject("Excel.Application")
Set objWB = objExcel.Workbooks.Open("c:\Acme Inc\Workbooks\Test.xls")
Set objSheet = objExcel.ActiveWorkbook.Worksheets(1)

' Make Excel visible while debugging
objExcel.Visible = True

' This is the row of our first cell.
x = 1

do while objExcel.Cells(x, 1).Value <> ""
strTemp = strTemp & objExcel.Cells(x, 1).Value & _
Space(10 - Len(objExcel.Cells(x, 1).Value))
strTemp = strTemp & objExcel.Cells(x, 2).Value & _
Space(50 - Len(objExcel.Cells(x, 2).Value))
strTemp = strTemp & objExcel.Cells(x, 3).Value & vbCRLF
x = x + 1
loop

' This will prevent Excel from prompting us to save the workbook.
objExcel.ActiveWorkbook.Saved = True

' Close the workbook and exit the application.
objWB.Close
objExcel.Quit

set objWB = Nothing
set objExcel = Nothing

GetData = strTemp
End Function

' This is our main function.
Dim strBody

Set objMessage = CreateObject("CDO.Message")
objMessage.Subject = "Inventory report for " & Date
objMessage.From = "me@my.com"
objMessage.To = "bossman@my.com"
strBody = "Part" & Space(6) & "Item" & Space(46) & "Stock" & vbCRLF

' Here we call the function GetData to populate the body text.
strBody = strBody & GetData

objMessage.TextBody = strBody
objMessage.Send

The code above will produce an email that looks something like this:

To: bossman@my.com
From: me@my.com
Subject: Inventory report for 3/19/2005

Part Item Stock
4583586 Fliggalhopper 452
5898547 Looplonger 293


This sample sends a simple text email via GMail servers.

It's like any other mail but requires that you set the SMTP Port to 465 and tell CDO to use SSL

Const cdoSendUsingPickup = 1 'Send message using the local SMTP service pickup directory.
Const cdoSendUsingPort = 2 'Send the message using the network (SMTP over the network).

Const cdoAnonymous = 0 'Do not authenticate
Const cdoBasic = 1 'basic (clear-text) authentication
Const cdoNTLM = 2 'NTLM

Set objMessage = CreateObject("CDO.Message")
objMessage.Subject = "Example CDO Message"
objMessage.From = """Me"" "
objMessage.To = "me@my.com"
objMessage.TextBody = "This is some sample message text.." & vbCRLF & "It was sent using SMTP authentication and SSL."

'==This section provides the configuration information for the remote SMTP server.

objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2

'Name or IP of Remote SMTP Server
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtp.gmail.com"

'Type of authentication, NONE, Basic (Base64 encoded), NTLM
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = cdoBasic

'Your UserID on the SMTP server
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusername") = "You@gmail.com"

'Your password on the SMTP server
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendpassword") = "YourPassword"

'Server port (typically 25)
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 465

'Use SSL for the connection (False or True)
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpusessl") = True

'Connection Timeout in seconds (the maximum time CDO will try to establish a connection to the SMTP server)
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 60

objMessage.Configuration.Fields.Update

'==End remote SMTP server configuration section==

objMessage.Send


3/19/10

7 Things Never to Say to Your Boss

Everyone has a boss. Even if you "work for yourself," you're still an employee to your client.

A big part of maintaining the boss-employee relationship is to never allow a boss to think you dislike your work, are incapable of doing it, or--worse--consider it beneath you.

[See the best careers for 2010.]

These sound like no-brainers, but many statements heard commonly around the workplace violate these basic rules. Looking for an example? Here are seven heard in workplaces all the time. They may seem ordinary, even harmless. But try reading these from your boss's point of view. You'll see right away why it's smart to never allow these seven sentences to pass your lips:

"That's not my job." You know what? A lot of bosses are simple souls who think your job is to do what's asked of you. So even if you're assigned a task that is, indeed, not your job, refrain from saying so. Instead, try to find out why your boss is assigning you this task--there may be a valid reason. If you believe that doing the task is a bad idea (as in, bad for the company) you can try explaining why and suggesting how it could be better done by someone else. This may work, depending on the boss. In any case, remember that doing what's asked of you, even tasks outside your job description, is good karma.

[See the 50 worst job interview mistakes.]

"It's not my problem." When people say something is not their problem it makes them look like they don't care. This does not endear them to anybody, especially the boss. If a problem is brewing and you have nothing constructive to say, it's better to say nothing at all. Even better is to pitch in and try to help. Because, ultimately, a problem in the workplace is everyone's problem. We're all in it together.

"It's not my fault." Yet another four words to be avoided. Human nature is weird. Claiming that something is not our fault often has the result of making people suspect it is. Besides, what's the real issue here? It's that something went wrong and needs to be fixed. That's what people should be thinking about--not who is to blame.

"I can only do one thing at a time." News flash: Complaining you are overworked will not make your boss feel sorry for you or go easier on you. Instead, a boss will think: (1) you resent your job, and/or (2) you aren't up to your job. Everybody, especially nowadays, feels pressured and overworked. If you're trying to be funny, please note that some sarcasm is funny and lightens the mood. Some just ticks people off.

[See how to answer 10 tricky interview questions.]

"I am way overqualified for this job." Hey, maybe you are. But the fact is, this is the job you have. You agreed to take it on and, while you may now regret that decision, it's still your job. Complaining that it's beneath you only makes you look bad. Plus, coworkers doing similar jobs may resent and dislike you. And guess what? Bosses will not think, "Oh, this is a superior person whom I need to promote." Nope, they'll think, "What a jerk."

"This job is easy! Anyone could do it!" Maybe what you're trying to convey here is that you're so brilliant your work is easy. Unfortunately, it comes off sounding more like, "This work is stupid." Bosses don't like hearing that any work is stupid. Nor do they really like hearing that a job is easy peasy. It belittles the whole enterprise. If a task is simple, be glad and do it as quickly as you can. Even "stupid" work needs to get done.

"It can't be done." Saying something can't be done is like waving a red flag in a boss's eyes. Even if the thing being suggested truly is impossible, saying it is can make you look ineffectual or incapable. Better to play detective. Why is the boss asking you to do whatever it is? What's the problem that needs to be solved? What's the goal? Search for doable ways of solving that problem or reaching that goal. That's what bosses really want. Most of them do not expect the impossible.

Last words: When in doubt, remember that silence really is golden.