home


Send emails from sql server asynchronously
Author Nigel Rivett

Note that none of this is tested (or maybe even compiled).
It was written in response to someone who wanted a guide.
I may get round to completing it one day.
This allows you to place emails in a table on the requesting server and to send them from a centerl email server.
Note the email sending is here implemented in sql server, which is maybe not a good thing.
The main objectives are to prevent the source process being effected by email problems, keep a record of emails sent and to allow emails to be batched or saved for sending later.
To change the sending code just replace xp_sendmail by nr_sendmail in the correct database.

--********************
--**** client objects
--********************

-- Table to hold emails to send
if exists (select * from dbo.sysobjects where id = object_id(N'[nr_Email]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [nr_Email]
GO
create table nr_Email
	(
	id 		int identity ,
	recipients	varchar(256) ,
	Subject		varchar(256) ,
	Message		varchar(1000) ,
	Copy_Recipients	varchar(256) ,
	Attachments	varchar(1000) ,
	Created		datetime default getdate() ,
	User		varchar(128) default system_user() ,
	sent		datetime
	)
go
create unique index ix_nr_Email_01 on nr_Email
	(id)
go

if exists (select * from dbo.sysobjects where id = object_id(N'[nr_Email_CommonData]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [nr_Email_CommonData]
GO
create table nr_Email_CommonData
	(
	id	varchar(20) ,
	Data	varchar(200)
	)
go
create unique index ix_nr_Email_CommonData_01 on nr_Email_CommonData
	(id)
go
insert nr_Email_CommonData (id, Data) select 'AttachmentPath', 'c:\temp\'

-- Replacement for xp_sendmail
create proc nr_SendMail
@recipients		varchar(26) ,
@Subject		varchar(256) ,
@Message		varchar(1000) ,
@Copy_Recipients	varchar(256) ,
@Attachments		varchar(1000) ,
@Query			varchar(1000)
as
declare @file varchar(1000)
	if @Query is not null and retrim(@Query) <> ''
	begin
		select @file = value from nr_Email_CommonData where id = 'AttachmentPath'
		select @file = @file + 'nr_mail_' + convert(varchar(20),@@spid) + '_' + convert(varchar(8),getdate(),112) + '_' + replace(convert(varchar(8),getdate(),108),':','') + '.csv'
		
		exec ('bcp "' + @Query + '" queryout "' + @file + '" -T -c -S' + @@servername)
		
		select @Attachments = coalesce(@Attachments + ';','') + @file
	end
	insert	nr_Email
		(
		recipients ,
		Subject ,
		Message ,
		Copy_Recipients ,
		Attachments
		)
	select	
		@recipients ,
		@Subject ,
		@Message ,
		@Copy_Recipients ,
		@Attachments
go

create proc nr_EmailLastSent
	(id int)
go
insert nr_EmailLastSent select 0
go

Create proc nr_EmailGet
@num	int
as
	set rowcount @num
	select 	*
	from	nr_Email
	where id > (select id from nr_EmailLastSent)
	order by id
go

Create proc nr_EmailMarkSent
@id
as
	update	nr_EmailLastSent
	set	id = @id
go

--********************
--**** server objects
--********************

Create proc nr_EmailControl
@server varchar(128) ,
@workDir varchar(128)
as

declare	@sql 	varchar(1000) ,
	@id 	int ,
	@maxid	int

declare	@recipients		varchar(256) ,
	@Subject		varchar(256) ,
	@Message		varchar(1000) ,
	@Copy_Recipients	varchar(256) ,
	@Attachments		varchar(1000)
	
	create table #a
		(
		id 			int ,
		recipients		varchar(256) ,
		Subject			varchar(256) ,
		Message			varchar(1000) ,
		Copy_Recipients		varchar(256) ,
		Attachments		varchar(1000) ,
		Created			datetime default getdate() ,
		User			varchar(128) default system_user() ,
		sent			datetime
		)
	
	select @sql = 'exec ' + @server + '.admin.dbo.nr_EmailGet'
	insert	#a
	exec (@sql)
	
	select	@id = 1 , @maxid = max(id) from #a
	
	while @id < @maxid
	begin
		select	@id = min(id) from #a where id > @id
		
		select 	@recipients		= recipients ,
			@Subject		= Subject ,
			@Message		= Message ,
			@Copy_Recipients	= Copy_Recipients ,
			@Attachments		= Attachments
		from	#a
		where	id = @id	
		
		if @AttachFile is not null
		begin
			select @sql = 'xcopy ' + @AttachFileDir + @AttachFileName + ' ' + @workDir
			select 	@AttachFileName = @workDir + @AttachFileName
			exec (@sql)
		end
		exec	master..xp_sendmail
				@recipients		= recipients ,
				@Subject		= Subject ,
				@Message		= Message ,
				@Copy_Recipients	Copy_Recipients
				@attachments		= @AttachFileName
		select @sql = 'exec ' + @server + '.admin.dbo.nr_EmailMarkSEnt ' + convert(varchar(20), @id)
		exec (@sql)
	end
go





home