Send SMTP Email from SQL Server with an extended stored procedure and a free COM component

By Peter A. Bromberg, Ph.D.

Peter Bromberg

 

SQL Server has a built - in system stored procedure, xp_sendmail, that allows you to send out email. Unfortunately, it requires the use of the MAPI provider through either Exchange or Outlook (a.k.a. "Windows Messaging"). Although some third party mail tools, such as Lotus Notes, offer MAPI providers, I have found that even the Microsoft MAPI interface can be both bulky and buggy at times. It's also very difficult to find a stand-alone installable version of Windows Messaging for Windows 2000, because it seems that Microsoft has conveniently decided to leave it out. At least, I couldn't find one!



So, how can we reliably send SMTP outgoing email if we can't have Outlook installed on the server that runs our SQL Server? Well, we can use a third - party COM SMTP component, along with the sp_OACreate system extended stored procedure family, to write our own stored procedure. Once this is done, we can find all kinds of useful applications for this. For example, you may have a table that holds certain version information on new builds that your department installs on a software application you're developing. You'd like to be able to send the proper personnel a notification email whenever a new "build" record has been inserted in this table.

With this sproc, you can add an "ON INSERT" trigger to the table, which will call your email sproc and automatically send out the required email. Pretty nifty. And when you add in the FREEWARE email component I'm going to show you, it gets even better. (I did say "FREE", didn't I - I've included it in the download zip file for this article because it's hard to find).

So, let's get started. The email component I've chosen is Rainking's "RKMAIL". It's only about 110K, and offers both SMTP and POP functions. It supports a lot of methods including attachments and multiple outbound mailservers (in case the first fails, it keeps going down the list). I'm only using a basic subset of features here, but certainly enough to get you going if you want to build added functionality.

 

First, we need to understand how the sp_OACreate extended sproc and it's brothers and sisters work.

Here's the syntax to create a registered COM component instance:

sp_OACreate progid, | clsid, objecttoken OUTPUT [ , context ]

Once it's created, we can access its properties and methods with the sp_OAGetProperty, sp_OASetProperty, and sp_OAMethod brethren.

So, for example to instantiate the RKMAIL component, the code looks like this:

EXEC @intResult = sp_OACreate 'RKMAIL.SMTP', @intObject OUT

intResult is the return code that we check for errors (and I'll get to that code in a moment), and intObject OUT is the output parameter that gives us a "handle" to the object we've created. We'll use this when we call the related sprocs to invoke methods, set or get properties.

To invoke the "add host" method of the RKMAIL component, we would do like this:

EXEC @intResult = sp_OAMethod @intObject, 'AddSMTPHost', NULL, @strSMTPServer

In the stored procedures I've included in the downloadable code accompanying this article, I've interspersed plenty of comments as well as providing error handling / checking code in the proc. I've also provided a sample ASP page using VBscript that has a form allowing the user to enter the email details, then calls the stored procedure and passes the form variables to it. The stored procedure sp_SendRKMail also allows you to pass in a comma - delimited list of multiple recipients. The way we handle this is as follows:

-- Parse and Add Recipients from comma - delimited @RecipientList
select @substring = ''
select @string = @RecipientList
select @string_length = len(@string)
select @startpos = 1
select @endpos = 1

while @startpos <= @string_length and @endpos <= @string_length + 1
begin
if substring(@string,@endpos,1) = ',' or @endpos > @string_length
begin
select @strToEmail = substring(@string,@startpos,@endpos-@startpos)
-- add recipient here to RKMail
EXEC @intResult = sp_OAMethod @intObject, 'AddRecipient', NULL, @strToName, @strToEmail
IF @intResult <> 0
BEGIN
EXEC sp_displayoaerrorinfo @intObject, @intResult
RETURN
END
-- set @strToName to null string so doesn't get repeated for multiple recips
select @strToName= ''
select @startpos = @endpos + 1
select @endpos = @startpos + 1
end
select @endpos = @endpos + 1

end

Finally when all the methods and properties are set, we call the Send() method and destroy our object:

 

--Send the mail
EXEC @intResult = sp_OAMethod @intObject, 'SendMail'
IF @intResult <> 0
BEGIN
EXEC sp_displayoaerrorinfo @intObject, @intResult
RETURN
END
-- Destroy mail object.
EXEC @intResult = sp_OADestroy @intObject
IF @intResult <> 0
BEGIN
EXEC sp_displayoaerrorinfo @intObject, @intResult
RETURN
END

The complete code for the above sproc as well as the error-handling sproc, OAErrorInfo are included in the download. Also included is the readme.txt file for all the methods and properties for both SMTP and POP in the control, the ASP test page I mentioned above, and my special ADOFunctions.asp "include" page that has a VBScript class that "genericizes" most of the methods a developer needs to work with SQL Server through ADO.

To get this going, simply register the included RKMAIL.DLL component (a good idea is to put it in a COM+ application), run the OAErrorInfo.sql and the sp_SendRKMail.sql SQL Server script files against your MASTER database, and put the ADOfunctions.asp and the SendRKMailSample.asp page in an IIS http-addressable virtual folder. ADOFunctions.asp is looking for Application("strConn") to be holding the connection string to your SQL Server database, so you'll need to set your virtual root to be an application and put that into a global.asa file. Otherwise, you'll need to hard-code in the connection string details.

Enjoy.

Nota Bene:
Reader Robert Klaproth was kind enough to send this valuable update:

"Thanks for the useful code for sending mail through SQL using RKMail. Unfortunately, there is one correction that I think you need to make to your article. There is a bug in SQL 6.5 and SQL 7 with the sp_OASetProperty that only allows 250 characters to be passed. This works fine for most of the paremeters needed to send the mail, but in the actual text of the mail, if you exceed 250 characters, it truncates your mail. This is unfortunate, because I was hoping to use SQL Server to send the mails instead of another methood. Unfortunately, this bug applies to ALL mailer .dll's including the CDONTS.
It is documented on Microsoft's site if you want to see the KBASE article it's: http://support.microsoft.com/support/kb/articles/Q278/4/48.ASP"

Download the code for this article

Peter Bromberg is an independent consultant specializing in distributed .NET solutions Inc. in Orlando and a co-developer of the NullSkull.com developer website. He can be reached at info@eggheadcafe.com