使用 sp_send_dbmail 将电子邮件动态发送给多个收件人

Sending email dynamically to multiple recipients with message using sp_send_dbmail

其实我想给成员们送上生日祝福。我正在动态获取收件人列表。通过以下查询,我可以向成员发送问候。

DECLARE @emails VARCHAR(500)
DECLARE @bodycontent VARCHAR(500)
SET @emails = '' 
SET @bodycontent = ''
use dnname
SELECT @emails = @emails + cm.PersonalEmail + ';' FROM tblIndividualMst  im
       inner join tblContactMst cm on cm.ContactID = im.ContactID
       where im.GroupID = 4673 and im.DateOfBirth = CONVERT(VARCHAR(10),GETDATE(),110)
DECLARE @recipList VARCHAR(500)
SET @recipList =  (select SUBSTRING(@emails, 0, LEN(@emails)))
SELECT @bodycontent = 'Happy BirthDay to'+ ' ' + + @bodycontent + 
       im.FullName + '' FROM tblIndividualMst  im
       inner join tblContactMst cm on cm.ContactID = im.ContactID
       where im.GroupID = 4673 and im.DateOfBirth = CONVERT(VARCHAR(10),GETDATE(),110)
use msdb
EXEC sp_send_dbmail @profile_name='eMail Profile',
    @recipients=@recipList,
    @subject='Happy Birthday',
    @body=@bodycontent, 
    @body_format = 'text'

那么,如果@emails 有多个收件人,我该如何将邮件发送给每个成员。

DECLARE @emails VARCHAR(500)
DECLARE @bodycontent VARCHAR(500)
SET @emails = '' 
SET @bodycontent = ''
use dnname
SELECT @emails = @emails + cm.PersonalEmail + ';' FROM tblIndividualMst  im
       inner join tblContactMst cm on cm.ContactID = im.ContactID
       where im.GroupID = 4673 and im.DateOfBirth = CONVERT(VARCHAR(10),GETDATE(),110)
DECLARE @recipList VARCHAR(500)
SET @recipList =  (select SUBSTRING(@emails, 0, LEN(@emails)))
SELECT @Count = @Count + Count(cm.PersonalEmail) FROM tblIndividualMst  im
       inner join tblContactMst cm on cm.ContactID = im.ContactID
       where im.GroupID = 4673 and im.DateOfBirth = CONVERT(VARCHAR(10),GETDATE(),110)

Declare @i int
set @i = 0
while @i <= @Count 
  begin
SELECT @bodycontent = 'Happy BirthDay to'+ ' ' + + @bodycontent + 
       im.FullName + '' FROM tblIndividualMst  im
       inner join tblContactMst cm on cm.ContactID = im.ContactID
       where im.GroupID = 4673 and im.DateOfBirth = CONVERT(VARCHAR(10),GETDATE(),110)
use msdb
EXEC sp_send_dbmail @profile_name='eMail Profile',
   @recipients=@recipList,
   @subject='Happy Birthday',
   @body=@bodycontent,  
   @body_format = 'text'
end

那么,我该如何修改我的查询。感谢任何帮助,谢谢!!!

这里有一些观察...

  1. 您还没有在代码中的任何地方声明 @Count。它需要声明为 INT 并设置为 0
  2. 在你的 WHILE LOOP 中你没有递增 @Count 所以这个循环是无限的
  3. 我会@emails varchar(max)以避免收件人列表被截断
  4. 据我所知,
  5. @recipList 毫无意义……您将其设置为 substring,从 0 开始,一直到所有电子邮件的整个长度……这是同样的说法 set @recipList = @emails
  6. 您的 while 循环的构造不符合您希望它如何工作的逻辑。看起来您的意图是发送一封电子邮件,其中包含所有生日的名字。首先,我会在@body 中用逗号分隔这些名称。其次,您根本不需要循环。删除 WHILE 循环,因为您需要做的就是将电子邮件发送一次,发送到您已构建的 @recipList 列表,并连接 @bodycontent

综上所述...您的代码可以简化为下面应该有效的代码。

use dnname

DECLARE @emails VARCHAR(max)
DECLARE @bodycontent VARCHAR(max)
DECLARE @people varchar(max) 
SET @emails = '' 
SET @people = ''
SET @bodycontent = ''



SELECT @emails = @emails + cm.PersonalEmail + ';' FROM tblIndividualMst  im
       inner join tblContactMst cm on cm.ContactID = im.ContactID
       where im.GroupID = 4673 and im.DateOfBirth = CONVERT(VARCHAR(10),GETDATE(),110)


SELECT @people = @people + im.FullName + ', ' 
       FROM tblIndividualMst  im
       inner join tblContactMst cm on cm.ContactID = im.ContactID
       where im.GroupID = 4673 and im.DateOfBirth = CONVERT(VARCHAR(10),GETDATE(),110)

SELECT @bodycontent = 'Happy BirthDay to '+ @people

EXEC msdb.dbo.sp_send_dbmail 
                           @profile_name='eMail Profile',
                           @recipients=@emails,
                           @subject='Happy Birthday',
                           @body=@bodycontent,  
                           @body_format = 'text'

如果您想为每个人发送一封个性化的电子邮件...您可以使用光标

use dnname

DECLARE @emails VARCHAR(4000)
DECLARE @bodycontent VARCHAR(max)
DECLARE @people varchar(4000) 
SET @emails = '' 
SET @people = ''
SET @bodycontent = ''

DECLARE emailCursor CURSOR FOR

SELECT cm.PersonalEmail,im.FullName 
FROM tblIndividualMst  im
inner join tblContactMst cm on cm.ContactID = im.ContactID
where im.GroupID = 4673 and im.DateOfBirth = CONVERT(VARCHAR(10),GETDATE(),110)

OPEN emailCursor
FETCH NEXT FROM emailCursor INTO  @emails, @people

WHILE @@FETCH_STATUS = 0
BEGIN

SET @bodycontent = 'Happy BirthDay to '+ @people

EXEC msdb.dbo.sp_send_dbmail 
                           @profile_name='eMail Profile',
                           @recipients=@emails,
                           @subject='Happy Birthday',
                           @body=@bodycontent,  
                           @body_format = 'text'

FETCH NEXT FROM emailCursor INTO  @emails, @people



END
CLOSE emailCursor
DEALLOCATE emailCursor

我个人反对在 SQL 中使用循环,因此尽量避免使用它们。这背后的想法是尽可能少地执行语句。在这种情况下,我会生成一段动态 SQL 并执行它。

DECLARE @SQL NVARCHAR(MAX);
SELECT @SQL = CAST((
    SELECT [text()] = REPLACE(REPLACE('
        EXEC msdb.dbo.sp_send_dbmail 
            @profile_name=''eMail Profile'',
            @recipients=''{email}'',
            @subject=''Happy Birthday'',
            @body=''Happy BirthDay to {fullname}'',  
            @body_format = ''text'';
    '
    ,'{fullname}',im.FullName)
    ,'{email}',cm.PersonalEmail)
    FROM tblIndividualMst  im
        INNER JOIN tblContactMst cm 
            ON cm.ContactID = im.ContactID
    WHERE im.GroupID = 4673 
        AND im.DateOfBirth = CAST(GETDATE() AS DATE)
    FOR XML PATH('')
) AS NVARCHAR(max));
EXEC sp_executesql @SQL;

让我解释一下我在这里做什么:

声明 @SQL 并将查询的结果分配给 NVARCHAR(max)。

DECLARE @SQL NVARCHAR(MAX);
SELECT @SQL = CAST((

XML 引擎用于连接字符串,这比使用普通连接要快得多,[text()] 确保 XML 标签不会包围 SQL 代码。

    SELECT [text()] = REPLACE(REPLACE('

这是要生成的 SQL 代码模板,其中包含将被替换的占位符。

        EXEC msdb.dbo.sp_send_dbmail 
            @profile_name=''eMail Profile'',
            @recipients=''{email}'',
            @subject=''Happy Birthday'',
            @body=''Happy BirthDay to {fullname}'',  
            @body_format = ''text'';
    '

替换占位符 ,'{全名}',im.FullName) ,'{电子邮件}',cm.PersonalEmail) 将定义需要多少次迭代的查询。

    FROM tblIndividualMst  im
        INNER JOIN tblContactMst cm 
            ON cm.ContactID = im.ContactID
    WHERE im.GroupID = 4673 
        AND im.DateOfBirth = CAST(GETDATE() AS DATE)

告诉 SQL 为这个查询生成 XML 但是通过提供一个空字符串并使用 [text()] 我们已经确保结果中没有实际包含标签。

    FOR XML PATH('')

将 XML 转换为 NVARCHAR(max)

) AS NVARCHAR(max));

最后执行!

EXEC sp_executesql @SQL;