sp_send_dbmail sending mail even if condition is false - SQL - sql

I have an IF statement part of a stored procedure as follows :
BEGIN TRY
IF EXISTS (SELECT which I have confirmed returns no results, has a variable called from another table in the where clause)
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#profile_name = #dynamic_profile,
#recipients = #dynamic_recipient,
#subject = #subjectline,
#body = #mailHTML,
#body_format = 'HTML';
END
END TRY
This is tied to a job that runs every 15mins.
Why is it keep sending me blank emails when the IF statement asks to skip the mail sending if the select returns no results?
My NOCOUNT is set to ON

Try - instead:
IF (SELECT COUNT(*) FROM whatever) > 0
BEGIN
--MAIL
END

Related

Bulk Update Email Trigger

I created a update trigger in Microsoft SQL Server that would email me if a date changed in a row.
Similar to this:
IF UPDATE(ColumnName)
BEGIN
DECLARE #columnVal AS DATETIME
SELECT
#columnVal = i.columnName
FROM
inserted i JOIN deleted d on i.RowId= d.RowId;
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'me',
#recipients = 'me#company.com',
#body = 'blah blah datechange',
#body_format = 'HTML',
#subject = 'subject';
END
it worked fine for a time.
Then I switched over to batch updates and only the first row email is sent out if the date changes on multiple rows. I tried to set up a cursor to roll through the changes but I cannot get it to work, Similar to below:
DECLARE #columnVal AS DATETIME
DECLARE cur CURSOR LOCAL READ_ONLY FAST_FORWARD FOR
SELECT
i.ColumnName
FROM
inserted i JOIN deleted d on i.RowId= d.RowId;
OPEN cur
FETCH NEXT FROM cur INTO #columnVal
WHILE ##FETCH_STATUS = 0
BEGIN
IF UPDATE(ColumnName)
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'me',
#recipients = 'me#company.com',
#body = 'blah blah datechange',
#body_format = 'HTML',
#subject = 'subject';
END
FETCH NEXT FROM cur INTO #columnVal
END
CLOSE cur
DEALLOCATE cur
Any ideas on how to accomplish this task? Would the Update(ColumnName) function even work properly nested inside a cursor (would it actually tell me if that column was updated for that row?)
A cursor inside a trigger is a very very bad idea.
A trigger should be very lean - it shouldn't do a lot of work! I would recommend to only "take a note" of who you have to send an e-mail to - but leave the actual sending of the e-mail to a separate e.g. SQL Server Agent Job which is not part of the trigger.
Triggers are fired often and often unexpectedly - don't put a log of processing burden into them! And especially not a performance killer like a cursor!
To find those rows that you're interested in, you can use a WHERE clause something like:
WHERE inserted.ColumnName <> deleted.ColumnName
In the context of an UPDATE trigger, this means the new value of ColumnName is different from the old value --> this column has been updated.

Agent job that emails from custom email table

I used to have triggers in my database that used cursors / sp_send_dbmail to email when certain columns were updated. I was told this was not best practice so I created a new table called EmailNotify that contains columns like recepient, subject, body etc. So instead the triggers now insert into this table the email I want to send.
I want to create a Job that runs every few minutes that checks this table and emails. The item below is what I came up with but is it okay to use cursors in this case? Should the table include a sent field so I know which rows I sent? Can I change that inside the cursor? Or would it be recommended to truncate the table afterwards?
DECLARE #emailSubject AS NVARCHAR(100);
DECLARE #emailRecipients AS NVARCHAR(100);
DECLARE #emailBody AS NVARCHAR(max);
DECLARE cur CURSOR LOCAL READ_ONLY FAST_FORWARD FOR
SELECT
recipients,
subject,
body
FROM
EmailNotify;
OPEN cur
FETCH NEXT FROM cur INTO
#emailRecipients,
#emailSubject,
#emailBody
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'name',
#recipients = #emailRecipients,
#body = #emailBody,
#body_format = 'HTML',
#subject = #emailSubject;
FETCH NEXT FROM cur INTO
#emailRecipients,
#emailSubject,
#emailBody
END
CLOSE cur
DEALLOCATE cur
I would
Add an EmailSent(DATETIME) = NULL column to your table
Create an EmailSent variable at the top of your proc and set it to GETDATE()
UPDATE <YOURTABLE> SET EmailSent = #EmailSent WHERE EmailSent IS NULL
Add a WHERE EmailSent = #EmailSent to your query for the email
You can accomplish this with a SSRS report with a subscription or data-bound subscription instead of this job, but it's really just a matter of preference. Formatting is easier in SSRS, otherwise you're messing with dynamic HTML in your message body. Been there, not pleasant.

Does anyone know why this code is sending users duplicate emails?

We have a stored procedure that is supposed to check db and select all records where sentFlag is No.
Once record(s) found, the stored proc invokes sp_send_dbmail with passed parameters and then sends an email to affected individuals.
This appears to work.
The issue we are having so far though is that each indivual is receiving duplicate emails.
Any ideas what part of this code could be causing this?
OPEN MAIL_CURSOR
FETCH MAIL_CURSOR into #mail1, #sender,#content1
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #email = #email+';'+Email
FROM GRVRIEVANCES
WHERE sentFlag = 'No'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Grievances',
#recipients = #email,
#subject = 'Account Details',
#body = #content1;
FETCH MAIL_CURSOR INTO #mail1, #sender, #content1
END
CLOSE MAIL_CURSOR
DEALLOCATE MAIL_CURSOR
END
If you set email to an initial value within the loop, does the issue go away? Also, make sure you setting the sentflag to 'yes'.
WHILE ##FETCH_STATUS = 0
BEGIN
SET #email=''
SELECT #email = #email+';'+Email
Back to basics to solve this one.
Start with some debugging:
Comment out your EXEC part
Add PRINT #email in the same spot
Run the cursor and see the reults, they should be quite enlightening!
Essentially what you're doing is on every cursor execution you are building up this big ol' string of email addresses for all GRVRIEVANCES WHERE sentFlag = 'No'.

SQL mail ------DATABASE MAIL

Dear all,
I am using SQL Server 2008.
I am facing a scenario where I have to send mail to single or multiple user depending on the query. I tried this stmt to send mail to multiple recipients
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'imran' ,
#recipients= 'imran.khan#bbraun.com;amol.puranik#bbraun.com',
#subject = 'Test mail'
It succesfully sent mail.
Now I want to send mail depending on query. With single employee it is no issue, but if it is more then one employee how can I mail to multiple recipients.
That is my question is in this sp to send multiple recipients one has to separate addresses with ; . How can I arrange recipients so that the ; comes in between.
Thank you.
Unfortunately, you're not giving us a lot to go on - you don't show us the query to select your employees, you're not telling us anything about what the Employee table looks like, so all we can do is guessing - at best.
So here's my guess: you want to somehow select multiple employees, and their e-mail addresses should be concatenated together, separated by a semicolon (;), and then used for your sp_send_dbmail call.
One method to do this could be this:
DECLARE #recipients VARCHAR(4000)
SELECT
#recipients = STUFF((SELECT ';' + EMail
FROM dbo.Employees
WHERE (some condition here to find the right employees)
FOR XML PATH('')
), 1, 1, '')
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'imran',
#recipients,
#subject = 'Test mail'
Use a function like this -
CREATE FUNCTION coltocsv
(
--your input parameters
)
RETURNS nvarchar(3000)
AS
BEGIN
-- Declare the return variable here
declare #keywords nvarchar(3000)
--Build your csv string of keywords
Select #keywords = null
SELECT #Keywords = Coalesce(#Keywords + '; ', '') +
ColumnName
from Table
where <some condition>
--- Return the result of the function
RETURN #keywords
END
for the recipients, you can seggregate the miultiple email id's by [];
declare #ccmailid varchar(2000);
select #ccmailid = stuff((select '],['+ mailid from table_name
order by '],['+ mailid
for xml path('')),1,2,'')+']'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'imran' ,
#recipients= #ccmailid,
#subject = 'Test mail'

Testing the result set of an sp_send_dbmail query?

I'm trying to send an email using sp_send_dbmail in Sql Server 2005. I have both body text and a query being sent as an attachment.
Sometimes, however, the query will return an empty dataset.
Is there any way for me to test the results of the dataset before I send out the email, and if it has no results, not send it as an attachment.
I was thinking to maybe run the query before I send the email, and to test the results that way. Then, I'd have an if-else as follows:
if ##rowcount >0
EXEC msdb.dbo.sp_send_dbmail #recipients=#recipients_list,
#subject = #subject,
#body = #body_text, #body_format = 'HTML',
#query = #query,
#attach_query_result_as_file = 1,
#query_result_width = 4000,
#query_attachment_filename = 'Details.txt'
else
EXEC msdb.dbo.sp_send_dbmail #recipients=#recipients_list,
#subject = #subject,
#body = #body_text, #body_format = 'HTML'
But I don't think this is an efficient way to solve the problem.
Any suggestions? TIA!!
Alright, I couldn't test this on my set up at work since it appears our DBAs have blocked access to this procedure. However, I know that sp_send_dbmail will not use local variables in the calling script, but it might let you use a global temp table.
This isn't a great solution, but you could try inserting your query result set into ##tempTable, then changing the query you pass to sp_send_dbmail to select * from ##tempTable if there are > 0 rows.
That should at least be better than running the original query 2x (if it works). Remember to drop it when you're done!