Home All Groups Group Topic Archive Search About

problems sending email from a trigger

Author
6 Sep 2006 2:40 PM
Jeff
Hey

MS Sql Server 2005

My trigger below isn't sending emails, the problem is in this code
"@recipients= 'select userEmail from inserted', ", I replaced that select
statement with a real email address and then it works

Any suggestions on what I should do make the select statement work is very
welcome

create trigger Send_Email on Test_Table for update
as
set nocount on;
exec msdb.dbo.sp_send_dbmail
    @profile_name='newbie',
    @recipients= 'select userEmail from inserted',
    @subject='test',
    @body='some text here',
    @body_format='TEXT';
go

Author
6 Sep 2006 3:22 PM
Tracy McKibben
Jeff wrote:
Show quote
> Hey
>
> MS Sql Server 2005
>
> My trigger below isn't sending emails, the problem is in this code
> "@recipients= 'select userEmail from inserted', ", I replaced that select
> statement with a real email address and then it works
>
> Any suggestions on what I should do make the select statement work is very
> welcome
>
> create trigger Send_Email on Test_Table for update
> as
>  set nocount on;
>  exec msdb.dbo.sp_send_dbmail
>     @profile_name='newbie',
>     @recipients= 'select userEmail from inserted',
>     @subject='test',
>     @body='some text here',
>     @body_format='TEXT';
> go
>
>

Operations such as this are just asking for trouble when placed into a
trigger.  Ignoring your actual problem for a minute, what will happen if
DBMail hangs?  Your trigger will be hung, resulting in a hung
transaction with locks that don't get released.  If DBMail performs
poorly and takes 2 minutes to send a message, your trigger will take 2
minutes to complete, resulting in a transaction that hold locks open for
2 minutes.

The proper way to do what you're trying to do is to stuff the list of
email addresses (SELECT userEmail FROM inserted) into a staging table.
That's all your trigger needs to do.  A seperate process, running from a
scheduled job, will monitor that staging table.  When it sees a new
record in the table, it grabs that record, sends an email to the address
contained within, then deletes the record.  Rinse, repeat.

--
Tracy McKibben
MCDBA
http://www.realsqlguy.com
Author
6 Sep 2006 3:28 PM
Aaron Bertrand [SQL Server MVP]
> scheduled job, will monitor that staging table.  When it sees a new record
> in the table, it grabs that record, sends an email to the address
> contained within, then deletes the record.

Or marks the row as processed, in case you want to keep the rows around for
auditing purposes.  If these are going out to end users outside of your
balance sheet, with the level of spam and phishing complaints around e-mail,
it might not be a bad idea to keep track of it...

A
Author
6 Sep 2006 3:33 PM
Jeff
wow, thanks for that great advice.


Show quote
"Tracy McKibben" <tr***@realsqlguy.com> wrote in message
news:44FEE7BB.5080205@realsqlguy.com...
> Jeff wrote:
>> Hey
>>
>> MS Sql Server 2005
>>
>> My trigger below isn't sending emails, the problem is in this code
>> "@recipients= 'select userEmail from inserted', ", I replaced that select
>> statement with a real email address and then it works
>>
>> Any suggestions on what I should do make the select statement work is
>> very welcome
>>
>> create trigger Send_Email on Test_Table for update
>> as
>>  set nocount on;
>>  exec msdb.dbo.sp_send_dbmail
>>     @profile_name='newbie',
>>     @recipients= 'select userEmail from inserted',
>>     @subject='test',
>>     @body='some text here',
>>     @body_format='TEXT';
>> go
>
> Operations such as this are just asking for trouble when placed into a
> trigger.  Ignoring your actual problem for a minute, what will happen if
> DBMail hangs?  Your trigger will be hung, resulting in a hung transaction
> with locks that don't get released.  If DBMail performs poorly and takes 2
> minutes to send a message, your trigger will take 2 minutes to complete,
> resulting in a transaction that hold locks open for 2 minutes.
>
> The proper way to do what you're trying to do is to stuff the list of
> email addresses (SELECT userEmail FROM inserted) into a staging table.
> That's all your trigger needs to do.  A seperate process, running from a
> scheduled job, will monitor that staging table.  When it sees a new record
> in the table, it grabs that record, sends an email to the address
> contained within, then deletes the record.  Rinse, repeat.
>
> --
> Tracy McKibben
> MCDBA
> http://www.realsqlguy.com
Author
6 Sep 2006 6:36 PM
Roger Wolter[MSFT]
Or have the trigger write the mail into a Service Broker queue (although
DBMail does this already to avoid the problems you mentioned).

--
This posting is provided "AS IS" with no warranties, and confers no rights.
Use of included script samples are subject to the terms specified at
http://www.microsoft.com/info/cpyright.htm

Show quote
"Tracy McKibben" <tr***@realsqlguy.com> wrote in message
news:44FEE7BB.5080205@realsqlguy.com...
> Jeff wrote:
>> Hey
>>
>> MS Sql Server 2005
>>
>> My trigger below isn't sending emails, the problem is in this code
>> "@recipients= 'select userEmail from inserted', ", I replaced that select
>> statement with a real email address and then it works
>>
>> Any suggestions on what I should do make the select statement work is
>> very welcome
>>
>> create trigger Send_Email on Test_Table for update
>> as
>>  set nocount on;
>>  exec msdb.dbo.sp_send_dbmail
>>     @profile_name='newbie',
>>     @recipients= 'select userEmail from inserted',
>>     @subject='test',
>>     @body='some text here',
>>     @body_format='TEXT';
>> go
>
> Operations such as this are just asking for trouble when placed into a
> trigger.  Ignoring your actual problem for a minute, what will happen if
> DBMail hangs?  Your trigger will be hung, resulting in a hung transaction
> with locks that don't get released.  If DBMail performs poorly and takes 2
> minutes to send a message, your trigger will take 2 minutes to complete,
> resulting in a transaction that hold locks open for 2 minutes.
>
> The proper way to do what you're trying to do is to stuff the list of
> email addresses (SELECT userEmail FROM inserted) into a staging table.
> That's all your trigger needs to do.  A seperate process, running from a
> scheduled job, will monitor that staging table.  When it sees a new record
> in the table, it grabs that record, sends an email to the address
> contained within, then deletes the record.  Rinse, repeat.
>
> --
> Tracy McKibben
> MCDBA
> http://www.realsqlguy.com
Author
6 Sep 2006 3:25 PM
Arnie Rowland
Hi,

Sample changes to your code below. I added a check for @@ROWCOUNT at the top so the trigger doesn't do anything if there are no rows updated (could happen if a constraint aborts the UPDATE.) Also added a [TOP 1] to prevent an error in case there were multiple row updates. However, only one email will be sent in that case.

CREATE TRIGGER Send_Email
   ON Test_Table
      FOR UPDATE
AS
   IF @@ROWCOUNT = 0
      RETURN

   SET NOCOUNT ON;

   DECLARE @UserEmail varchar(200)

   SELECT TOP 1 @UserEmail = UserEmail
   FROM   inserted
   ORDER BY UserEmail

   EXECUTE msdb.dbo.sp_send_dbmail
      @profile_name  = 'newbie',
      @recipients    = @UserEmail,
      @subject       ='test',
      @body          ='some text here',
      @body_format   ='TEXT';
GO

--
Arnie Rowland, Ph.D.
Westwood Consulting, Inc

Most good judgment comes from experience.
Most experience comes from bad judgment.
- Anonymous


Show quote
"Jeff" <it_consultant1@NO_SPAM.hotmail.com> wrote in message news:uxvhHJc0GHA.772@TK2MSFTNGP05.phx.gbl...
> Hey
>
> MS Sql Server 2005
>
> My trigger below isn't sending emails, the problem is in this code
> "@recipients= 'select userEmail from inserted', ", I replaced that select
> statement with a real email address and then it works
>
> Any suggestions on what I should do make the select statement work is very
> welcome
>
> create trigger Send_Email on Test_Table for update
> as
> set nocount on;
> exec msdb.dbo.sp_send_dbmail
>    @profile_name='newbie',
>    @recipients= 'select userEmail from inserted',
>    @subject='test',
>    @body='some text here',
>    @body_format='TEXT';
> go
>
>
Author
6 Sep 2006 3:25 PM
Aaron Bertrand [SQL Server MVP]
@recipients= 'select userEmail from inserted',

1) you can't have a query as a string like that and expect it to be
magically interpreted and executed.
2) what happens if your update affects four rows?  Contrary to popular
misconception, a trigger fires once per statement, not once per row.

First, you will need something like this:

IF @@ROWCOUNT = 1
BEGIN
    DECLARE @to NVARCHAR(4000);
    SELECT @to = userEmail FROM inserted;

    EXEC msdb.dbo.sp_send_dbmail
        @recipients = @to,
        ...;
END
IF @@ROWCOUNT > 1
BEGIN
    -- now you need something here
    -- to loop and either concatenate
    -- or send an e-mail for each row
    -- affected, UGH UGH UGH UGH
END

However, in a more general sense, sending an email from a trigger is a very
bad idea.  I would rather insert the e-mail addresses into a queue table and
have a job wake up every minute and send an e-mail for each row.  This would
prevent all the contention this trigger is going to have, and solves the
multi-row update problem quite cleanly.

A





Show quote
"Jeff" <it_consultant1@NO_SPAM.hotmail.com> wrote in message
news:uxvhHJc0GHA.772@TK2MSFTNGP05.phx.gbl...
> Hey
>
> MS Sql Server 2005
>
> My trigger below isn't sending emails, the problem is in this code
> "@recipients= 'select userEmail from inserted', ", I replaced that select
> statement with a real email address and then it works
>
> Any suggestions on what I should do make the select statement work is very
> welcome
>
> create trigger Send_Email on Test_Table for update
> as
> set nocount on;
> exec msdb.dbo.sp_send_dbmail
>    @profile_name='newbie',
>    @recipients= 'select userEmail from inserted',
>    @subject='test',
>    @body='some text here',
>    @body_format='TEXT';
> go
>

AddThis Social Bookmark Button