尝试触发器发送电子邮件时,SQL触发器不起作用

时间:2011-02-17 23:08:23

标签: sql-server sql-server-2008 triggers

我正在尝试创建一个数据库触发器,当插入一个新行时会触发该数据库触发器,该新行具有一个特定的单词,它将发送电子邮件警报。当我运行该代码时,电子邮件警报就会起作用,如果我删除了电子邮件并将其替换为其他内容,则触发器会起作用。

以下是代码:

ALTER TRIGGER CheckForDirty
ON dbo.Messages
FOR INSERT,UPDATE
AS

DECLARE @MESSAGETEXT varchar(max)
DECLARE @BADWORD1 varchar(50)

SET @MESSAGETEXT = (SELECT Body FROM inserted)
SET @BADWORD1 = 'BadWord'

IF CHARINDEX(@BADWORD1, @MESSAGETEXT) > 0
BEGIN

    EXEC msdb.dbo.sp_send_dbmail @recipients='message@email.com',
    @subject = 'Test e-mail sent from database mail',
    @body = 'Someone said something dirty'

END
GO

2 个答案:

答案 0 :(得分:1)

首先猜测是权限。当您手动运行电子邮件时,您运行的帐户是否与执行触发器时不同?在您测试用户帐户下的代码然后在具有较少权限的其他帐户下运行应用程序之前,我已经看到了这一点。您需要确保所有用户都在正确的邮件组中。

答案 1 :(得分:1)

建议您将电子邮件发送代码与触发器分离 - 在触发器中,将所需信息插入“待定电子邮件”表中。然后创建一个定期检查表并发送电子邮件的作业。

您还需要重新编写触发器以应对多行插入和更新。 inserted是一个可以包含多行的伪表。

所以我会写一个这样的触发器:

CREATE TRIGGER CheckForDirty
ON dbo.Messages
FOR INSERT,UPDATE
AS

INSERT INTO PendingEmails (Recipients,Subject,Body)
SELECT 'message@email.com','Test e-mail sent from database mail','Someone said something dirty'
FROM inserted
WHERE CHARINDEX('BadWord',Body) > 0

虽然我假设您构建的邮件的实际正文可能依赖于更多信息来帮助识别哪些邮件被牵连。


好的,如果我们要将其构建成一个完整的示例,我们需要定义PendingEmails:

CREATE TABLE PendingEmails (
    PendingEmailID int IDENTITY(1,1) not null,
    Recipients varchar(max) not null,
    Subject nvarchar(255) not null,
    Body nvarchar(max) not null,
    constraint PK_PendingEmails PRIMARY KEY (PendingEmailID)
)

现在我们将编写一个可以处理待处理电子邮件的存储过程:

CREATE PROCEDURE DispatchPendingEmails
AS
     declare @PendingEmailID int
     declare @Recipients varchar(max)
     declare @Subject nvarchar(255)
     declare @Body nvarchar(max)

     while exists(select * from PendingEmails)
     begin
         select top 1 @PendingEmailID = PendingEmailID,@Recipients = Recipients,
             @Subject = Subject, @Body = Body from PendingEmails

         exec msdb.dbo.sp_send_dbmail @recipients = @Recipients, @subject = @Subject, @body = @Body

         delete from PendingEmails where PendingEmailID = @PendingEmailID
     end

最后,我们需要创造这份工作。我通常通过SSMS执行此操作,但是如果您希望它编写脚本(您需要在sp_add_jobstep行中替换不同的数据库名称,并且设置为每五分钟运行一次调度。所有存储过程都很好记录在MSDN中):

USE [msdb]
GO
DECLARE @jobId BINARY(16)
EXEC  msdb.dbo.sp_add_job @job_name=N'DispatchPendingEmails', 
        @enabled=1, 
        @notify_level_eventlog=0, 
        @notify_level_email=2, 
        @notify_level_netsend=2, 
        @notify_level_page=2, 
        @delete_level=0, 
        @category_name=N'[Uncategorized (Local)]', 
        @owner_login_name=N'sa', @job_id = @jobId OUTPUT
select @jobId
GO
EXEC msdb.dbo.sp_add_jobserver @job_name=N'DispatchPendingEmails', @server_name = N'SYSTEMS86\SQL2K8'
GO
USE [msdb]
GO
EXEC msdb.dbo.sp_add_jobstep @job_name=N'DispatchPendingEmails', @step_name=N'ExecSP', 
        @step_id=1, 
        @cmdexec_success_code=0, 
        @on_success_action=1, 
        @on_fail_action=2, 
        @retry_attempts=0, 
        @retry_interval=0, 
        @os_run_priority=0, @subsystem=N'TSQL', 
        @command=N'exec DispatchPendingEmails', 
        @database_name=N'Database', --<-- This needs editing
        @flags=0
GO
USE [msdb]
GO
EXEC msdb.dbo.sp_update_job @job_name=N'DispatchPendingEmails', 
        @enabled=1, 
        @start_step_id=1, 
        @notify_level_eventlog=0, 
        @notify_level_email=2, 
        @notify_level_netsend=2, 
        @notify_level_page=2, 
        @delete_level=0, 
        @description=N'', 
        @category_name=N'[Uncategorized (Local)]', 
        @owner_login_name=N'sa', 
        @notify_email_operator_name=N'', 
        @notify_netsend_operator_name=N'', 
        @notify_page_operator_name=N''
GO
USE [msdb]
GO
DECLARE @schedule_id int
EXEC msdb.dbo.sp_add_jobschedule @job_name=N'DispatchPendingEmails', @name=N'QuiteOften', 
        @enabled=1, 
        @freq_type=4, 
        @freq_interval=1, 
        @freq_subday_type=4, 
        @freq_subday_interval=5, 
        @freq_relative_interval=0, 
        @freq_recurrence_factor=1, 
        @active_start_date=20110218, 
        @active_end_date=99991231, 
        @active_start_time=0, 
        @active_end_time=235959, @schedule_id = @schedule_id OUTPUT
select @schedule_id
GO