|
Building a Mail Queue SystemBy Damian Maclennen on 24 September 2001 | Tags: SQLMail This article demonstrates an email queue system using SQL Server and VB Script. This overcomes the limitations of the Sending SMTP Mail using a Stored Procedure method. In a previous article I demonstrated a way to send email from a stored procedure using a COM object. This article prompted a lot of comments and discussion. From this discussion a few things became evident.
In short, although this method is fine for say, sending alert emails to an administrator, for a large scale emailing solution it does not really work. Another wayA different approach to this problem is to put all emails into a "Queue" table. Then use a scheduled job (running every minute or so) to poll this table and send any mail in the queue. For the purpose of this article, I am going to demonstrate a simple solution for this, then outline some ways you could make it more robust. The Queue TableFirstly, create a "Mail Queue" table. Create Table MailQueue( MailDate DateTime Default(GetDate()), FromName VarChar(200) NOT NULL, FromAddress VarChar(200) NOT NULL, ToName VarChar(200) NOT NULL, ToAddress VarChar(200) NOT NULL, Subject VarChar(200) NOT NULL, Body VarChar(6000) NOT NULL ) This is fairly straightforward. We have a timestamp column, the details of the sender and recipient of the email, the subject and the body. Getting Data InThe next step is getting data into the table. For this we can use two methods, firstly is a single email method, second is inserting a batch of emails. For a single email, this procedure will work. Create Procedure SendMail @FromName VarChar(200), @FromAddress VarChar(200), @ToName VarChar(200), @ToAddress VarChar(200), @Subject VarChar(200), @Body VarChar(6000) AS --Inserts mail into queue table INSERT Into MailQueue (FromName, FromAddress, ToName, ToAddress, Subject, Body) Values (@FromName, @FromAddress, @ToName, @ToAddress, @Subject, @Body) Calling this procedure is easy. Exec SendMail 'Me', 'me@mydomain.com', 'you', 'you@yourdomain.com', 'Hi', 'The body of the message' Another way to get mail into the queue would be to do an insert using a select. Here is an example : Declare @FromName VarChar(200), @FromAddress VarChar(200), @Subject VarChar(200), @Body VarChar(200) Select @FromName = 'Me', Select @FromAddress = 'me@mydomain.com' Select @Subject = 'Hi there' Select @Body = 'The body of the message' --Insert mail into queue table INSERT Into MailQueue (FromName, FromAddress, ToName, ToAddress, Subject, Body) Select @FromName, @FromAddress, UserFirstName + ' ' + UserSurname, UserEmail, @Subject, @Body FROM Users As you can see, this will insert a row in the Queue table for every user in the fictional Users table. Sending mailO.K. we have rows in our queue table, now what ? What we want to do is write a program that will get all the rows in our queue table and send an email for each one, we would typically want to run continuously. In this case, I am going to write some VBScript and run it as a SQL Server scheduled job. I am going to write a stored procedure to get the rows out of the table. Once I have retrieved them, I want to delete them from the queue. To avoid any rows being inserted between my select and my delete, I am going to use a temp table. Create Procedure GetMailQueue AS Set Nocount on --Select from queue into a temp table. Then delete from Queue. --This gets around any issues with mail being inserted between select and delete Create Table #tempmail( MailDate DateTime Default(GetDate()), FromName VarChar(200) NOT NULL, FromAddress VarChar(200) NOT NULL, ToName VarChar(200) NOT NULL, ToAddress VarChar(200) NOT NULL, Subject VarChar(200) NOT NULL, Body VarChar(6000) NOT NULL ) Insert Into #tempmail Select * From MailQueue Delete From MailQueue From MailQueue M INNER JOIN #tempmail t ON t.MailDate = M.MailDate Select * From #tempmail drop table #tempmail Set Nocount Off This procedure will return a set containing all the mails from the queue. Here is the VBScript code to retrieve the set and send it. Once again, I have used the ASPMail component from ServerObjects, but you could modify it to use CDONTS or JMail or whatever other component you use. For a complete VBScript reference go to The Microsoft Scripting site.
'--------------------
'ADO Constants
Const adCmdStoredProc = &H0004
'--------------------
'System config
Const ConnString = "Provider=SQLOLEDB; Data Source=(local); Initial Catalog=testing;
User ID=test; Password=test"
Const MailServer = "mail.mydomain.com"
Call Main
Sub Main()
dim sFromName, sFromAddress, sToName, sToAddress, sSubject, sBody
dim objCmd, objRs
'ADO Command Object
Set objCmd = CreateObject("ADODB.Command")
objCmd.ActiveConnection = ConnString
objCmd.CommandType = adCmdStoredProc
objCmd.CommandText = "GetMailQueue" 'Our Stored procedure
Set objRS = objCmd.execute 'Gets an ADO recordset of all the emails
do until objRs.EOF 'Loop through the emails
sFromName = objRs("FromName")
sFromAddress = objRs("FromAddress")
sToName = objRs("ToName")
sToAddress = objRs("ToAddress")
sSubject = objRs("Subject")
sBody = objRs("Body")
'Call our mail subroutine
Call SendMail(sFromName, sFromAddress, sToName, sToAddress, sSubject, sBody)
objRS.movenext
loop
'Clean up
objRS.close
Set objRS = nothing
Set objCmd = nothing
End Sub
Sub SendMail(sFromName, sFromAddress, sToName, sToAddress, sSubject, sBody)
dim objMail, errCode
'Create the mail object
Set objMail = CreateObject("SMTPsvg.Mailer")
'Set all the properties for this email
objMail.RemoteHost = MailServer
objMail.FromName = sFromName
objMail.FromAddress = sFromAddress
objMail.AddRecipient sToName, sToAddress
objMail.Subject = sSubject
objMail.BodyText = sBody
'Send it
errCode = objMail.SendMail
'Clean up
Set objMail = nothing
End Sub
Running ItThe next step is to set this script up as a job. You can do this in Enterprise Manager, schedule a script task to fire every minute. ConclusionThere you have it, a simple mail queue system. As I said before there are ways of making it more robust but I wanted to make the example simple to understand. Some ways of making it better:
I hope this example has got you thinking about other features you could incorporate. The main point of this aricle as well as the last one on mail is to remind you that there is always another way to do things, and with a little bit of lateral thinking you can come up with a solution to fit your needs. The source code to these examples is here. Have fun with it. Happy coding!
|
- Advertisement - |