Explanation:
My guess is that the code you are actually using is slightly different from the code you have posted here because when I take your code and the following data in a test database, things work out fine.
create table email_archive
(
id int,
emailed_to nvarchar(255)
)
insert into email_archive values
( 1, '[email protected]'), ( 2, '[email protected]'), ( 3, '[email protected]'),
( 4, '[email protected]'), ( 5, '[email protected]'), ( 6, '[email protected]'),
( 7, '[email protected]'), ( 8, '[email protected]'), ( 9, '[email protected]'),
(10, '[email protected]'), (11, '[email protected]'), (12, '[email protected]'),
(13, '[email protected]'), (14, '[email protected]'), (15, '[email protected]'),
(16, '[email protected]'), (17, '[email protected]'), (18, '[email protected]'),
(19, '[email protected]'), (20, '[email protected]'), (21, '[email protected]')
I am thinking you may have hit upon an issue discussed here: http://bit.ly/cMlnjt
Since I can't be sure I offer you two alternative solutions that will definitely get the job done, even though as others have mentioned this aggregate concatenation should work without an issue.
Alternatives:
To get what you are looking for, I prefer one of the following two options
1) Just make sp_send_dbmail do the work for you.
2) Go with a cursor solution
Option 1:
EXEC msdb..sp_send_dbmail @profile_name = 'MyMailProfile',
@recipients = '[email protected]',
@subject = 'Runaway Email Monitor',
@body = 'Runaway emails found',
@query = 'SELECT COUNT(*), emailed_to FROM mydb.dbo.email_archive GROUP BY emailed_to HAVING COUNT(*) > 5 ORDER BY COUNT(*) DESC'
Note: The having clause makes this only display rows where the count is greater than 5.
Option 2:
USE test
IF EXISTS ( SELECT name FROM test.sys.sysobjects WHERE type = 'P' AND name = 'usp_MonitorEmails' )
BEGIN
DROP PROCEDURE dbo.usp_MonitorEmails
END
GO
CREATE PROCEDURE usp_MonitorEmails
@Subject nvarchar(255) = '',
@Importance varchar(6) = 'NORMAL',
@Sensitivity varchar(12) = 'NORMAL',
@Recipients varchar(MAX) = NULL,
@MinimumCount int = 0
AS
BEGIN
SET NOCOUNT ON
IF UPPER(@Importance) NOT IN ('LOW', 'NORMAL', 'HIGH') SET @Importance = 'NORMAL'
IF UPPER(@Sensitivity) NOT IN ('NORMAL', 'PERSONAL', 'PRIVATE', 'CONFIDENTIAL') SET @Sensitivity = 'NORMAL'
DECLARE @run bit,
@message nvarchar(MAX)
SELECT @run = 0,
@subject = 'Run Away Email Monitor',
@message = 'Run away emails found' + CHAR(13)+CHAR(10) +
'Count Email Address' + CHAR(13)+CHAR(10) +
'----------- ------------------------------------------------------------------------------' + CHAR(13)+CHAR(10)
DECLARE @count int,
@email nvarchar(255)
DECLARE BodyCursor CURSOR STATIC FOR
SELECT COUNT(*), emailed_to FROM email_archive GROUP BY emailed_to HAVING COUNT(*) > @MinimumCount ORDER BY COUNT(*) DESC
OPEN BodyCursor
FETCH NEXT FROM BodyCursor
INTO @count, @email
WHILE @@FETCH_STATUS = 0
BEGIN
SELECT @message = @message + REPLICATE(N' ', 11-LEN(CAST(@count AS nvarchar(22)))) + CAST(@count AS nvarchar(22)) + ' ' + @email + CHAR(13)+CHAR(10), @run = 1
FETCH NEXT FROM BodyCursor
INTO @count, @email
END
CLOSE BodyCursor
DEALLOCATE BodyCursor
IF @run = 1 AND LEN(@Recipients) > 0
BEGIN
EXEC msdb..sp_send_dbmail @profile_name = 'MyMailProfile',
@recipients = @Recipients,
@subject = @Subject,
@body = @Message,
@body_format = 'TEXT',
@importance = @Importance,
@sensitivity = @Sensitivity
END
END
GO
Note: I prefer this method because of the flexibility I have in the way the messages are formatted. This will also only send the email if there are rows returned where the minimum count is reached.