說兩句:在某人最困難的時候,寫下此文,寄給某某報想騙點稿費,結果石沉大海,若干年后,翻騰硬盤翻出來了。呵呵,或許可以對希望在sqlserver中發送郵件的網友有所幫助。
54powerman^_^
sql mail技術給每一位數據庫開發人員和dba(數據庫管理員)帶來了極大的方便,利用該技術,sql server數據庫代理程序可以在系統出現異常的時候自動發送email通知管理員,開發人可以利用它讓數據庫自動定期的修改用戶密碼,然后發送email通知用戶……等等這些應用,都不同程度上把我們從繁雜的工作中解放出來。但是,sql mail的配置是比較復雜的,相信90%以上的人在配置sql mail的時候都遇到過各種各樣的麻煩,至少有70%的人放棄了sql mail而選擇其他方案來解決這個問題。筆者是一名人員,親身經歷了這一切,并找到了一個更好的替代方法。不敢獨享,寫出來以饗讀者。
sql mail配置有幾種方式,按照支持軟件可劃分為基于exchange、outlook2000(以上)和第三方軟件的配置方案,三種方式各有利弊,主要表現在以下幾個方面:
使用outlook客戶端配合sql server實現sql mail
此方案軟件要求較低,只需要在sql server所在服務器上安裝outlook2000以上版本客戶端即可。它要求在sql mail使用期間,outlook客戶端必須打開,否則,只能到下次打開時,郵件才能發送出去。另外,如果服務器為遠程服務器,用微軟官方的遠程桌面無法完成配置,可替代的方案是dba親自去機房直接操作,或者安裝pcanywhere10替代遠程桌面進行操作。
使用exchange要求較高
microsoft推薦使用exchange作為sql mail的最佳拍檔,msdn的資料提出:“由于 pop3/smtp 協議存在的局限性和登錄問題,microsoft 建議您使用 exchange server 來實現可靠性”。但是exchange并不是專門做這個來使用的,可以說是屈才了,而且exchange要求服務器配置域管理器,相信這個東東對大多數數據庫服務器來說用處不大,只不過是浪費資源罷了。如果我們要在多臺服務器上配置sql mail那么就需要在每一臺服務器上配置域管理器,或者所有的服務器都配置到一個域內,但是對于服務器比較分散的系統來說這樣是不現實的。
使用第三方系統支持
微軟msdn稱:“如果您使用的是第三方郵件服務器,則必須將郵件服務器配置為 pop3 服務器。如果這些郵件服務器使用的本地郵件服務可能是由第三方郵件客戶端安裝的,microsoft 將不支持連接到這些服務器”。這就意味著你還要使用windows平臺的郵件服務,使用asp編寫網站的朋友一定都知道,cdonts.dll組件實在是……。
面對這些問題,筆者就變成了我剛才說的那70%了,雖然爬網無數,讀文字數萬把sql mail配置好了,但是我仍然絕對放棄,因為我不想在做第2臺、第3臺……的時候重蹈覆轍。替代的方案就是jmail組件+ole自動化對象,以上的問題迎刃而解。
預備知識
1.ole自動化函數
ole自動化使應用程序能夠對另一個應用程序中實現的對象進行操作,或者將對象公開以便可以對其進行操作。自動化客戶端是可對屬于另一個應用程序的公開對象進行操作的應用程序,本文值得是sql server。公開對象的應用程序稱為自動化服務器,又成為自動化組件,本文中即jmail組件咯??蛻舳送ㄟ^訪問應用程序對象的屬性和函數對這些對象進行操作。
在sql server使用ole組件的途徑是幾個系統擴展存儲過程sp_oacreate、sp_oadestroy、sp_oageterrorinfo、sp_oamethod、sp_oasetproperty和sp_oagetproperty,再次簡單地介紹一下使用方法,詳細資料參考sql server聯機叢書。
ole自動化對象的使用方法:
(1)調用 sp_oacreate 創建對象。
格式:sp_oacreate clsid,objecttoken output [ , context ]
參數:clsid——是要創建的 ole 對象的程序標識符 (progid)。此字符串描述該 ole 對象的類,其形式,如 'olecomponent.object',olecomponent 是 ole 自動化服務器的組件名稱,object 是 ole 對象名,本文中使用的“jmail.message”;
objecttoken——是返回的對象標志,并且必須是數據類型為 int 的局部變量。用于標識所創建的 ole 對象,并將在調用其它 ole 自動化存儲過程時使用。本文中就是通過它來調用jmail.message組件的屬性和方法的。
context——指定新創建的 ole 對象要在其中運行的執行上下文。本文不使用該參數,故不贅述。以下與此一致,所有方法屬性的其他用法請參閱sql server聯機文檔。
(2)使用該對象。
(a)調用 sp_oagetproperty 獲取屬性值。
格式:_oagetproperty objecttoken,propertyname [, propertyvalue output]
參數:(前面出現過的參數,以下均省略。)
propertyname——對象的屬性名稱;
propertyvalue——返回的對象的屬性值,該參數帶output屬性,執行該操作后,你就可以從propertyvalue中得到屬性的值了。
(b)調用 sp_oasetproperty 將屬性設為新值。
格式:sp_oasetproperty objecttoken, propertyname, propertyvalue
(c)調用 sp_oamethod 以調用某個方法。
格式:sp_oamethod objecttoken, methodname [, returnvalue output] [ , [ parametername = ] parametervalue [...n]]
參數:returnvalue——調用方法的返回值,如果沒有返回值,此參數設置為null;
parametername——方法定義中的參數名稱,也就是形參;
parametervalue——參數值;
……n——表示,可以帶很多參數,個數由方法定義限制;
(d)調用 sp_oageterrorinfo 獲取最新的錯誤信息。
格式:sp_oageterrorinfo [objecttoken ] [, source output] [, description output]
參數:source——錯誤源;
description——錯誤描述;
(3)調用 sp_oadestroy 釋放對象。
格式:sp_oadestroy objecttoken
2.xp_cmdshell擴展存儲過程
該擴展存儲過程在master數據庫中,它的全路徑是master..xp_cmdshell(注意,中間是2個點),它的功能是:以操作系統命令行解釋器的方式執行給定的命令字符串,并以文本行方式返回任何輸出。
格式:xp_cmdshell {'command_string'} [, no_output]
參數:'command_string'——是在操作系統命令行解釋器上執行的命令字符串。
no_output——是可選參數,表示執行給定的 command_string,但不向客戶端返回任何輸出。本文應用中不使用該參數。
操作方法
(1)軟件準備
請先到http://www.dimac.net/或者國內提供組件下載的網站下載最新版的jmail組件,如果你得到的是安裝版,執行wejmailx.exe即可,系統的配置安裝程序會自動完成。如果只有一個jmail.dll文件,請按照下面的步驟安裝:
(a)新建文本文件,輸入如下命令:
regsvr32 jmail.dll
net start w3svc
另存為install.bat(注意,千萬不要保存成install.bat.txt啊)
(b)此文件連同jmail.dll一起拷貝到sql server數據庫服務器的system32目錄下,并執行雙擊install.bat即可。
(2)準備好了嗎?跟我來吧
(a)運行sql server查詢分析器,并以sa身份登錄到sql server數據庫;
(b)如果你的存儲過程要添加到yourdefaultcatalog數據庫,請在空白sql窗口輸入如下指令,否則請相應修改數據庫名。
use yourdefaultcatalog
按f5或者運行按鈕運行該指令;
(c)創建基本發送存儲過程
復制如下代碼到sql server命令窗口,并運行。下面的代碼中有相應的注釋,文中不多做解釋,如有疑問請查看前面的“預備知識”或者查詢sql server幫助文件,當然也可以和作者聯系。
create procedure dbo.sp_jmail_send
@sender varchar(100),
@sendername varchar(100)='',
@serveraddress varchar(255)='smtp服務器地址',
@mailserverusername varchar(255)=null,
@mailserverpassword varchar(255)=null,
@recipient varchar(255),
@recipientbcc varchar(200)=null,
@recipientbccname varchar(200)=null,
@recipientcc varchar(200)=null,
@recipientccname varchar(100)=null,
@attachment varchar(100) =null,
@subject varchar(255),
@mailbody text
as
/*
該存儲過程使用辦公自動化腳本調用dimac w3 jmail axtivex組件來代替sql mail發送郵件
該方法支持“服務器端身份驗證”
*/
--聲明w3 jmail使用的常規變量及錯誤信息變量
declare @object int,@hr int,@rc int,@output varchar(400),@description varchar (400),@source varchar(400)
--創建jmail.message對象
exec @hr = sp_oacreate 'jmail.message', @object output
--設置郵件編碼
exec @hr = sp_oasetproperty @object, 'charset', 'gb2312'
--身份驗證
if not @mailserverusername is null
exec @hr = sp_oasetproperty @object, 'mailserverusername',@mailserverusername
if not @mailserverpassword is null
exec @hr = sp_oasetproperty @object, 'mailserverpassword',@mailserverpassword
--設置郵件基本參數
exec @hr = sp_oasetproperty @object, 'from', @sender
exec @hr = sp_oamethod @object, 'addrecipient', null , @recipient
exec @hr = sp_oasetproperty @object, 'subject', @subject
exec @hr = sp_oasetproperty @object, 'body', @mailbody
--設置其它參數
if not @attachment is null
exec @hr = sp_oamethod @object, 'addattachment', null , @attachment,'false'
print @attachment
if (not @recipientbcc is null) and (not @recipientbccname is null)
exec @hr = sp_oamethod @object, 'addrecipientbcc', null , @recipientbcc,@recipientbccname
else if not @recipientbcc is null
exec @hr = sp_oamethod @object, 'addrecipientbcc', null , @recipientbcc
if (not @recipientcc is null) and (not @recipientccname is null)
exec @hr = sp_oamethod @object, 'addrecipientcc', null , @recipientcc,@recipientccname
else if not @recipientcc is null
exec @hr = sp_oamethod @object, 'addrecipientcc', null , @recipientcc
if not @sendername is null
exec @hr = sp_oasetproperty @object, 'fromname', @sendername
--調用send方法發送郵件
exec @hr = sp_oamethod @object, 'send', null,@serveraddress
--捕獲jmail.message異常
exec @hr = sp_oageterrorinfo @object, @source output, @description output
if (@hr = 0)
begin
set @output='錯誤源: '[email protected]
print @output
select @output = '錯誤描述: ' + @description
print @output
end
else
begin
print '獲取錯誤信息失?。?
return
end
--釋放jmail.message對象
exec @hr = sp_oadestroy @object
(d)簡化存儲過程操作,以適合我們平時的使用習慣
上面的存儲過程基本可以完成郵件發送操作,但是非常冗長,而且不符合我們的習慣,比如它不支持多個發送給接收者、不支持將sql指令運行結果以附件形式發送(這是sql mail的功能,我們也可以做到)等,所以我們要再寫一個存儲過程來調用它,以簡化操作,并擴展功能。
create procedure sendmail
@sender varchar(50)=null,
@strrecipients varchar(200),
@strsubject varchar(200),
@strmessage varchar(2000),
@sql varchar(50)=null)
as
declare @splitstr varchar(1) --定義郵件地址分割符變量
declare @strtemp varchar(200) --定義多個收件人字符串臨時變量
declare @email varchar(50) --用分割符分割后的單個收件人字符串變量
declare @senderaddress varchar(50)
declare @attach varchar(200)
declare @defaultsender varchar(50)
declare @mailserver varchar(50)
declare @user varchar(50)
declare @pass varchar(50)
declare @sendername varchar(50)
declare @attachdir varchar(100)
--初始化缺省變量
set @defaultsender='缺省發送地址'
set @mailserver='郵件服務器地址'
set @user='smtp服務器驗證用戶地址'
set @pass='smtp服務器驗證地址'
set @sendername='缺省發件人名稱'
set @attachdir='e:/log/webdata/jmail/'+replace(replace(replace(convert(varchar(19),getdate(),120),'-',''),' ',''),':','')+'.txt'
--將email地址分割符統一為分號
set @splitstr=';'
set @[email protected][email protected]+'end'
set @strtemp=replace(@strtemp,',',';')
--判斷是否有sql語句
if (@sql is null) or (len(@sql)=0)
set @attachdir=null
else
begin
declare @cmdstr varchar(200)
set @cmdstr='bcp "'[email protected]+'" queryout '[email protected]+' -c'
exec master..xp_cmdshell @cmdstr
end
while charindex(@splitstr,@strtemp,1)<>0
begin
set @email=left(@strtemp,charindex(@splitstr,@strtemp,1)-1)
set @strtemp=right(@strtemp,len(@strtemp)-len(@email)-1)
if (@sender is null) or (len(@sender)=0)
set @[email protected]
else
set @[email protected]
print @email
--調用sp_jmail_send發送郵件
exec sp_jmail_send @[email protected],@[email protected],
@[email protected],@[email protected],@[email protected],
@[email protected],@[email protected],@[email protected],@[email protected]
end
此存儲過程只擴展了sql查詢結果附件發送,如果你要發送標準附件,請直接使用sp_jmail_send存儲過程或者自行擴展功能。
新聞熱點
疑難解答