SQL Mail 提供了一种从 Microsoft SQL Server 发送和阅读电子邮件的简单方法。但是,由于 SQL Mail 是一个 MAPI 应用程序,因此服务器上必须存在 MAPI 子系统。Microsoft Windows NT 4.0 会在您安装 Windows Messaging 时安装 MAPI 子系统。但是,Microsoft Windows 2000 不提供 MAPI 子系统。因此,如果您需要使用 SQL Mail,就必须安装诸如 Microsoft Outlook 之类的 MAPI 客户端。
您可以使用其他方法从 SQL Server 中直接发送简单邮件传输协议 (SMTP) 电子邮件。例如,可以配合 sp_OA SQL Server OLE 自动化存储过程使用 NT Server 协作数据对象 (CDONTS) 或 Windows 2000 协作数据对象 (CDOSYS)。本文将举例说明如何使用这些方法向 Internet 邮件服务器发送电子邮件。您可以修改这些方法以便它们能够提供更可靠的邮件系统。例如,您可能需要添加错误处理代码。这些示例中的方法不提供阅读或处理电子邮件的方法。
注意:从 Windows 2000 起开始提供 CDOSYS,因此,建议您用 CDOSYS 来代替 CDONTS。Windows Server 2003 及更高版本的操作系统都不支持 CDONTS。
Microsoft 提供的编程示例只用于说明目的,不附带任何明示或默示的保证。这包括但不限于对适销性或特定用途适用性的默示保证。本文假定您熟悉所演示的编程语言和用于创建和调试过程的工具。Microsoft 的支持工程师可以帮助解释某个特定过程的功能,但是他们不会修改这些示例以提供额外的功能或构建过程以满足您的特殊需求。
CDONTS 是一个特定于 OLE 服务器的简单邮件传输协议 (SMTP),专门用于向基于 Web 的应用程序提供邮件传输功能。因此,CDONTS 支持发送基于 HTML 的电子邮件。基于 Mapi 的应用程序(如 SQL Mail)则不支持。默认情况下,Microsoft Internet Information Server (IIS) 4.0 或更高版本会安装 CDONTS。默认情况下,Microsoft Windows 2000 会安装 Microsoft Internet Information Server (IIS) 5.0。
有关 CDONTS 的更多信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
当您使用 CDONTS 而不是 SQL Mail 时,不必在运行 SQL Server 的计算机上安装诸如 Microsoft Outlook 之类的邮件客户端。您也不必非得有一个 Microsoft Exchange 服务器。您可以将任何支持 SMTP 电子邮件的邮件服务器用作您的“智能主机”。但是,您将无法阅读和处理使用 CDONTS 发送到运行 SQL Server 的计算机上的电子邮件,也不能替代 SQL Agent Mail 的功能。
下面的说明是针对 Microsoft Windows 2000 的。如果计算机上安装了 IIS 4.0,可以使用类似的方法配置 Microsoft Windows NT 4.0。不过,所采取的步骤会略有不同。
有关如何在 Microsoft Windows NT 4.0 上配置“智能主机”的更多信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
exec sp_send_cdontsmail 'someone@example.com','someone2@example.com','Test of CDONTS','It works'
注意:只有“sysadmin”固定服务器角色的成员才可以运行 OLE 自动化存储过程。如果 SQL Server 用户不是“sysadmin”固定服务器角色的成员,则不能使用本例中提到的存储过程来发送电子邮件。在这种情况下,您可能必须开发一个客户端应用程序来通过 CDONTS 发送电子邮件。例如,您可以使用 Microsoft Visual Basic 应用程序。
因为 CDOSYS 可以向远程 SMTP 服务器发送电子邮件,因此 CDOSYS 不需要您在运行 SQL Server 的计算机上安装并运行 Internet Information Server。您也不必配置 SMTP 虚拟服务器。您要做的只是在 SQL Server 中创建一个可以用来发送电子邮件的存储过程。
当您使用 CDOSYS 而不是 SQL Mail 时,不必在运行 SQL Server 的计算机上安装诸如 Microsoft Outlook 之类的邮件客户端。您也不必非得有一个 Exchange 服务器。您可以将任何支持 SMTP 邮件的邮件服务器用作您的远程 SMTP 邮件服务器。但是,如果使用 CDOSYS,您将无法阅读或处理发送到 SQL Server 的电子邮件,也不能替代 SQL Agent Mail 的功能。
结合 SQL Server OLE 自动化对象使用 CDOSYS 依赖于 SQL Server OLE 自动化来调用 CDOSYS 对象模型。已在 SQL Server 2000 Service Pack 1 (SP1) 和 SQL Server 2000 Service Pack 2 (SP2) 中对此进行了测试。Microsoft 不保证能够从在 SQL Server 2000 SP1 之前发布的 SQL Server 版本中的 OLE 自动化存储过程调用 CDOSYS。
创建发送 CDOSYS 邮件的存储过程
您可以使用类似如下的代码在数据库中创建一个存储过程,使之通过使用 SQL Server OLE 自动化存储过程调用 CDOSYS 对象模型来发送电子邮件。
-- drop old cdosysmail_failures table if exists
IF (EXISTS (SELECT * FROM dbo.sysobjects WHERE name = N'cdosysmail_failures' AND type='U')) DROP TABLE [dbo].[cdosysmail_failures]
GO
-- Create new cdosysmail_failures table
CREATE TABLE [dbo].[cdosysmail_failures]
([Date of Failure] datetime,
[Spid] int NULL,
[From] varchar(100) NULL,
[To] varchar(100) NULL,
[Subject] varchar(100) NULL,
[Body] varchar(4000) NULL,
[iMsg] int NULL,
[Hr] int NULL,
[Source of Failure] varchar(255) NULL,
[Description of Failure] varchar(500) NULL,
[Output from Failure] varchar(1000) NULL,
[Comment about Failure] varchar(50) NULL)
GO
IF (EXISTS (SELECT * FROM dbo.sysobjects WHERE name = N'sp_send_cdosysmail' AND type='P')) DROP PROCEDURE [dbo].[sp_send_cdosysmail]
GO
CREATE PROCEDURE [dbo].[sp_send_cdosysmail]
@From varchar(100) ,
@To varchar(100) ,
@Subject varchar(100)=" ",
@Body varchar(4000) =" "
/*********************************************************************
This stored procedure takes the parameters and sends an e-mail.
All the mail configurations are hard-coded in the stored procedure.
Comments are added to the stored procedure where necessary.
References to the CDOSYS objects are at the following MSDN Web site:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdosys/html/_cdosys_messaging.asp
***********************************************************************/
AS
Declare @iMsg int
Declare @hr int
Declare @source varchar(255)
Declare @description varchar(500)
Declare @output varchar(1000)
--************* Create the CDO.Message Object ************************
EXEC @hr = sp_OACreate 'CDO.Message', @iMsg OUT
IF @hr <>0
BEGIN
SELECT @hr
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'Failed at sp_OACreate')
EXEC @hr = sp_OAGetErrorInfo NULL, @source OUT, @description OUT
IF @hr = 0
BEGIN
SELECT @output = ' Source: ' + @source
PRINT @output
SELECT @output = ' Description: ' + @description
PRINT @output
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'sp_OAGetErrorInfo for sp_OACreate')
RETURN
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
RETURN
END
END
--***************Configuring the Message Object ******************
-- This is to configure a remote SMTP server.
-- http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cdosys/html/_cdosys_schema_configuration_sendusing.asp
EXEC @hr = sp_OASetProperty @iMsg, 'Configuration.fields("http://schemas.microsoft.com/cdo/configuration/sendusing").Value','2'
IF @hr <>0
BEGIN
SELECT @hr
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'Failed at sp_OASetProperty sendusing')
EXEC @hr = sp_OAGetErrorInfo NULL, @source OUT, @description OUT
IF @hr = 0
BEGIN
SELECT @output = ' Source: ' + @source
PRINT @output
SELECT @output = ' Description: ' + @description
PRINT @output
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'sp_OAGetErrorInfo for sp_OASetProperty sendusing')
GOTO send_cdosysmail_cleanup
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
GOTO send_cdosysmail_cleanup
END
END
-- This is to configure the Server Name or IP address.
-- Replace MailServerName by the name or IP of your SMTP Server.
EXEC @hr = sp_OASetProperty @iMsg, 'Configuration.fields("http://schemas.microsoft.com/cdo/configuration/smtpserver").Value', cdoSMTPServerName
IF @hr <>0
BEGIN
SELECT @hr
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'Failed at sp_OASetProperty smtpserver')
EXEC @hr = sp_OAGetErrorInfo NULL, @source OUT, @description OUT
IF @hr = 0
BEGIN
SELECT @output = ' Source: ' + @source
PRINT @output
SELECT @output = ' Description: ' + @description
PRINT @output
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'sp_OAGetErrorInfo for sp_OASetProperty smtpserver')
GOTO send_cdosysmail_cleanup
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
GOTO send_cdosysmail_cleanup
END
END
-- Save the configurations to the message object.
EXEC @hr = sp_OAMethod @iMsg, 'Configuration.Fields.Update', null
IF @hr <>0
BEGIN
SELECT @hr
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'Failed at sp_OASetProperty Update')
EXEC @hr = sp_OAGetErrorInfo NULL, @source OUT, @description OUT
IF @hr = 0
BEGIN
SELECT @output = ' Source: ' + @source
PRINT @output
SELECT @output = ' Description: ' + @description
PRINT @output
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'sp_OAGetErrorInfo for sp_OASetProperty Update')
GOTO send_cdosysmail_cleanup
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
GOTO send_cdosysmail_cleanup
END
END
-- Set the e-mail parameters.
EXEC @hr = sp_OASetProperty @iMsg, 'To', @To
IF @hr <>0
BEGIN
SELECT @hr
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'Failed at sp_OASetProperty To')
EXEC @hr = sp_OAGetErrorInfo NULL, @source OUT, @description OUT
IF @hr = 0
BEGIN
SELECT @output = ' Source: ' + @source
PRINT @output
SELECT @output = ' Description: ' + @description
PRINT @output
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'sp_OAGetErrorInfo for sp_OASetProperty To')
GOTO send_cdosysmail_cleanup
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
GOTO send_cdosysmail_cleanup
END
END
EXEC @hr = sp_OASetProperty @iMsg, 'From', @From
IF @hr <>0
BEGIN
SELECT @hr
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'Failed at sp_OASetProperty From')
EXEC @hr = sp_OAGetErrorInfo NULL, @source OUT, @description OUT
IF @hr = 0
BEGIN
SELECT @output = ' Source: ' + @source
PRINT @output
SELECT @output = ' Description: ' + @description
PRINT @output
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'sp_OAGetErrorInfo for sp_OASetProperty From')
GOTO send_cdosysmail_cleanup
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
GOTO send_cdosysmail_cleanup
END
END
EXEC @hr = sp_OASetProperty @iMsg, 'Subject', @Subject
IF @hr <>0
BEGIN
SELECT @hr
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'Failed at sp_OASetProperty Subject')
EXEC @hr = sp_OAGetErrorInfo NULL, @source OUT, @description OUT
IF @hr = 0
BEGIN
SELECT @output = ' Source: ' + @source
PRINT @output
SELECT @output = ' Description: ' + @description
PRINT @output
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'sp_OAGetErrorInfo for sp_OASetProperty Subject')
GOTO send_cdosysmail_cleanup
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
GOTO send_cdosysmail_cleanup
END
END
-- If you are using HTML e-mail, use 'HTMLBody' instead of 'TextBody'.
EXEC @hr = sp_OASetProperty @iMsg, 'TextBody', @Body
IF @hr <>0
BEGIN
SELECT @hr
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'Failed at sp_OASetProperty TextBody')
EXEC @hr = sp_OAGetErrorInfo NULL, @source OUT, @description OUT
IF @hr = 0
BEGIN
SELECT @output = ' Source: ' + @source
PRINT @output
SELECT @output = ' Description: ' + @description
PRINT @output
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'sp_OAGetErrorInfo for sp_OASetProperty TextBody')
GOTO send_cdosysmail_cleanup
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
GOTO send_cdosysmail_cleanup
END
END
EXEC @hr = sp_OAMethod @iMsg, 'Send', NULL
IF @hr <>0
BEGIN
SELECT @hr
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'Failed at sp_OAMethod Send')
EXEC @hr = sp_OAGetErrorInfo NULL, @source OUT, @description OUT
IF @hr = 0
BEGIN
SELECT @output = ' Source: ' + @source
PRINT @output
SELECT @output = ' Description: ' + @description
PRINT @output
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'sp_OAGetErrorInfo for sp_OAMethod Send')
GOTO send_cdosysmail_cleanup
END
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
GOTO send_cdosysmail_cleanup
END
END
-- Do some error handling after each step if you have to.
-- Clean up the objects created.
send_cdosysmail_cleanup:
If (@iMsg IS NOT NULL) -- if @iMsg is NOT NULL then destroy it
BEGIN
EXEC @hr=sp_OADestroy @iMsg
-- handle the failure of the destroy if needed
IF @hr <>0
BEGIN
select @hr
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'Failed at sp_OADestroy')
EXEC @hr = sp_OAGetErrorInfo NULL, @source OUT, @description OUT
-- if sp_OAGetErrorInfo was successful, print errors
IF @hr = 0
BEGIN
SELECT @output = ' Source: ' + @source
PRINT @output
SELECT @output = ' Description: ' + @description
PRINT @output
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, 'sp_OAGetErrorInfo for sp_OADestroy')
END
-- else sp_OAGetErrorInfo failed
ELSE
BEGIN
PRINT ' sp_OAGetErrorInfo failed.'
RETURN
END
END
END
ELSE
BEGIN
PRINT ' sp_OADestroy skipped because @iMsg is NULL.'
INSERT INTO [dbo].[cdosysmail_failures] VALUES (getdate(), @@spid, @From, @To, @Subject, @Body, @iMsg, @hr, @source, @description, @output, '@iMsg is NULL, sp_OADestroy skipped')
RETURN
END
接下来使用您刚创建的存储过程并提供正确的参数。
declare @Body varchar(4000)
select @Body = 'This is a Test Message'
exec sp_send_cdosysmail 'someone@example.com','someone2@example.com','Test of CDOSYS',@Body
注意:只有“sysadmin”固定服务器角色的成员才可以运行 OLE 自动化存储过程。如果您的 SQL Server 用户不是“sysadmin”固定服务器角色的成员,则不能使用本例中提到的存储过程来发送电子邮件。在这种情况下,您可能必须开发一个客户端应用程序来通过 CDOSYS 发送邮件。例如,您可以使用 Microsoft Visual Basic 应用程序。
有关 SQL Server OLE 自动化存储过程的更多信息,请参阅 SQL Server 2000 联机丛书中的“SQL Server OLE 自动化存储过程”主题。
如果您没有看到您问题的答案,请访问 Microsoft SQL Server 新闻组,地址是:
Microsoft SQL Server 新闻组
(http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.server)
如果您想对本文或其他 Microsoft SQL Server 知识库文章发表评论,请给我们发邮件,地址是:
SQLKB@Microsoft.com
(mailto:sqlkb@microsoft.com)