I just can't see what I'm doing wrong but it's probably a simple issue.
I use sp_send_dbmail to send an email notification to users. The body of the email is formatted with html.
When I do tests, the body is blank. I've narrowed it down to the #Name variable. If I add a simple string like 'John' then the body is not blank, but I'm doing something wrong with the #Name variable.
I would think the CAST of #Name is unnecessary, but I've just been trying different things to no avail.
How do I incorporate #Name in a correct way?
Below is the code with parts of the irrelevant html left out to shorten it:
Alter Proc [dbo].[SendPayslipEmail]
(#TVP EmailAddressTableType READONLY,
#Period NVARCHAR(50),
#Message NVARCHAR(MAX))
as
begin
DECLARE #ResTag INT
DECLARE #Email_Address VARCHAR(150)
DECLARE #emailHTML NVARCHAR(MAX) ;
DECLARE #Subject NVARCHAR(50);
DECLARE #Name NVARCHAR(50);
DECLARE #LoginURL NVARCHAR(50);
SET #Subject = (Select [Value] from [CustomerEmailSettings] where [Setting] = 'Payslip Email Subject')
SET #LoginURL = (Select [Value] from [CustomerEmailSettings] where [Setting] = 'LoginURL')
DECLARE cursorSendEmail CURSOR
FOR SELECT [Resource Tag],[E-mail Address] FROM #TVP;
OPEN cursorSendEmail
FETCH NEXT FROM cursorSendEmail INTO #ResTag,#Email_Address;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Name = CAST((SELECT [Display Name] FROM DisplayName(#ResTag)) AS NVARCHAR(50))
SET #emailHTML =
N'<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">'
+N'<head>'
<!-- More html -->
+N'<p class=MsoNormal><b><span style=''color:#4485B8''>Dear '
+#Name
+N',<o:p></o:p></span></b></p>'
<!-- More html -->
+N'</html>'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'PayslipEmails',
#recipients = #Email_Address,
#body = #emailHTML,
#body_format = 'HTML',
#subject = #Subject;
FETCH NEXT FROM cursorSendEmail INTO #ResTag,#Email_Address;
END
CLOSE cursorSendEmail
DEALLOCATE cursorSendEmail
end
Related
I have a database in SQL Server that has a user table with 3 columns: name, date of birth and email.
I have a stored procedure that goes through this table looking for who is having a birthday today, and sends him a congratulatory email, so far it works at 100.
However, I want to add within the same procedure that I send an email to all the users of the database (except the one with a birthday), notifying them that x person are having a birthday today.
This is my current SQL Server code:
CREATE PROCEDURE spSendEmail
AS
DECLARE #email nvarchar(128)
DECLARE #name nvarchar(128)
DECLARE #Date date
SELECT
GETDATE(),
MONTH(GETDATE()), DAY(GETDATE()), YEAR(GETDATE())
DECLARE email_cursor CURSOR FOR
SELECT u.name, u.email
FROM dbo.users u
WHERE MONTH(u.dateofbirth) = MONTH(GETDATE())
AND DAY(u.dateofbirth) = DAY(GETDATE())
OPEN email_cursor
FETCH NEXT FROM email_cursor INTO #name, #email
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #email
DECLARE #subject nvarchar(255)
DECLARE #Bodytext nvarchar(512)
SET #BodyText = #Name + '' + 'we wish you happy birthday'
SET #Subject = 'Happy Birthday'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Birthday Alert',
#recipients = #email,
#body = #Bodytext,
#subject = #subject;
FETCH NEXT FROM email_cursor INTO #name, #email
END
CLOSE email_cursor
DEALLOCATE email_cursor
CREATE PROCEDURE spSendEmail AS
DECLARE #email nvarchar(128)
DECLARE #name nvarchar(128)
DECLARE #Date date
DECLARE #Num_Users_Having_Birthday varchar(100) = (SELECT COUNT(*) FROM dbo.users WHERE MONTH(u.dateofbirth) = MONTH(GETDATE())
AND DAY(u.dateofbirth) = DAY(GETDATE()))
SELECT
GETDATE(),
MONTH(GETDATE()), DAY(GETDATE()), YEAR(GETDATE())
DECLARE email_cursor CURSOR FOR
SELECT u.name, u.email
FROM dbo.users u
WHERE MONTH(u.dateofbirth) <> MONTH(GETDATE())
AND DAY(u.dateofbirth) <> DAY(GETDATE())
OPEN email_cursor
FETCH NEXT FROM email_cursor INTO #name, #email
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #email
DECLARE #subject nvarchar(255)
DECLARE #Bodytext nvarchar(512)
SET #BodyText = #Name
SET #Subject = 'Number of People having Birthday today:' + #Num_Users_Having_Birthday
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Birthday Alert',
#recipients = #email,
#body = #Bodytext,
#subject = #subject;
FETCH NEXT FROM email_cursor INTO #name, #email
END
CLOSE email_cursor
DEALLOCATE email_cursor
Try this:
CREATE PROCEDURE spSendEmail
AS
BEGIN
DECLARE #email nvarchar(128)
DECLARE #name nvarchar(128)
DECLARE #has_birthday BIT
DECLARE #Date date
DECLARE #birthday_boys INT -- update this to
SELECT
GETDATE(),
MONTH(GETDATE()), DAY(GETDATE()), YEAR(GETDATE())
IF(OBJECT_ID('tempdb..users') IS NOT NULL)
DROP TABLE #users;
-- For Sql Server version >= 2016: DROP TABLE IF EXISTS #users
SELECT u.name, u.email
, IIF(MONTH(u.dateofbirth) = MONTH(GETDATE()) AND DAY(u.dateofbirth) = DAY(GETDATE()),1,0) has_birthday
INTO #users
FROM dbo.users u
--Get all birthday boys list
SELECT #birthday_boys = COUNT(u.name)
FROM #users u
WHERE has_birthday = 1
DECLARE email_cursor CURSOR FOR
SELECT u.name, u.email, u.has_birthday
FROM #users
OPEN email_cursor
FETCH NEXT FROM email_cursor INTO #name, #email, #has_birthday
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT #email
DECLARE #subject nvarchar(255)
DECLARE #Bodytext nvarchar(512)
SET #BodyText = IIF(#has_birthday = 1, #Name + '' + 'we wish you happy birthday', CONCAT('Birthday boys'' count is ', #birthday_boys))
SET #Subject = IIF(#has_birthday = 1, 'Happy Birthday', 'Birthday Boys'' Count')
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Birthday Alert',
#recipients = #email,
#body = #BodyText,
#subject = #subject
FETCH NEXT FROM email_cursor INTO #name, #email
END
CLOSE email_cursor
DEALLOCATE email_cursor
IF(OBJECT_ID('tempdb..users') IS NOT NULL)
DROP TABLE #users;
-- For Sql Server version >= 2016: DROP TABLE IF EXISTS #users
END
Is there a way to make an automatic reminder via email when those dates comes and send the rows info from the same table, for example:
In the following table we have to columns with different dates, DUEDATE need to be a reminder from expedition and EXPDV is another reminder 15 day before DUEDATE, So when one of those dates from any row comes I want to make to send and automatic Reminder via email with the row info (PSLOT,PSQRCV,ETC) From that table , any ideas?
USE [database_name]
GO
SET NOCOUNT ON;
DECLARE #count INT =
(
SELECT COUNT(*) FROM dbo.TableName
WHERE DATEDIFF(DAY, EXPDV, DUEDATE) = 15
)
IF #count > 0
BEGIN
DECLARE #html NVARCHAR(max)
, #subject NVARCHAR(max) = 'Your email subject here'
, #email NVARCHAR(255)
, #PSLOT NVARCHAR(255)
, #PSQRCV NVARCHAR(255)
, #ETC NVARCHAR(255)
DECLARE send_remider CURSOR FOR
SELECT email, PSLOT,PSQRCV,ETC FROM dbo.TableName
WHERE DATEDIFF(DAY, EXPDV, DUEDATE) = 15
OPEN send_remider
FETCH NEXT FROM send_remider INTO #email, #PSLOT, #PSLOT, #ETC
WHILE ##FETCH_STATUS = 0
BEGIN
SET #html = 'Your message body text here....' + #PSLOT, #PSQRCV, #ETC
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'profile_name'
, #recipients = #email
, #subject = #subject
, #body = #html
, #body_format = 'HTML'
FETCH NEXT FROM send_remider INTO #email, #PSLOT, #PSLOT, #ETC
END
CLOSE send_remider
DEALLOCATE send_remider
GO
You can create a job and run this cursor. I haven't tested it. So, you should make yourself a recipient during testing.
I would like to know, how to include a variable as a part of a SQL statement, to clarify more about my question, here is the code
declare #PartNo as nvarchar(20)
declare #PPFno as nvarchar(20)
declare #Dimension as nvarchar(30)
declare #cursor CURSOR
declare #colname as nvarchar(30)
declare #top as integer
declare #query as nvarchar(MAX)
declare #categoryid NVARCHAR(MAX)
set #cursor = CURSOR FOR
(select [Name] from sys.columns where object_id = (select object_id from sys.tables where name = 'ProductProperty') and [Name] like 'T%' and [name] <> 'TEMP')order by [Name] asc
OPEN #cursor
FETCH NEXT
FROM #cursor INTO #colname
WHILE ##FETCH_STATUS = 0
BEGIN
--set #query = (select #colname from ProductProperty where PartNo = #PartNo and PPFNo = #PPFno )
--set #query = 'select distinct '+#colname+' from ProductProperty where PartNo = '''+#PartNo+''' and PPFNo = '''+#PPFno+''' and DName = '''+#Dimension+''''
BEGIN
EXEC sp_executesql N'set #categoryid = (select distinct #colname from ProductProperty where PartNo = #PartNo and PPFNo = #PPFno and DName = #Dimension)',
N'#colname nvarchar(30), #PartNo nvarchar(20), #PPFno nvarchar(20),#Dimension nvarchar(30), #categoryid NVARCHAR(MAX) OUTPUT', #colname,#PartNo, #PPFno,#Dimension, #categoryid OUTPUT
select #categoryid,#colname ,#PartNo
END
--end
FETCH NEXT
FROM #cursor INTO #colName
END
CLOSE #cursor
DEALLOCATE #cursor
Please do take note I did not included the variable types. I would just want to know how can #colname become part of the SQL Statement.
To Elaborate more. Using this code, I am receiving this data
Where T1 is the table name. I want to create a query where I could pass table names into a variable, then retrieve the contents of that query.
So the SQL Query should look like this:
select T1 from ProductProperty
But I am not receiving the query, instead, I am receiving the variable data, which is in the screenshot above.
The problem is, if you might notice in my code, I have the variable #categoryid as a output parameter. This is to check the contents of the query.
it seems like I am producing a query which looks like this
select 'T1' from ProductProperty
May I ask, what am I doing wrong? If you would want additional information, please do tell me.
EDIT:
completed the query for more clarification
The issue here is that you are telling it to select the value of the #colname variable itself as the first value in your query, not the value of the column name stored in the variable. This is the equivalent of doing:
SELECT #colname;
What you need to do is output the value of the #colname variable into the SQL string you are passing to sp_executesql. As long as the #colname variable isn't entered by the user, you can concatenate it into the string passed to sp_executesql, as follows:
DECLARE #SqlQuery NVARCHAR(MAX);
SET #SqlQuery = N'set #categoryid = (select distinct ' + #colname + ' from ProductProperty
where PartNo = #PartNo and PPFNo = #PPFno and DName = #Dimension)';
EXEC sp_executesql #SqlQuery,
#PartNo nvarchar(20), #PPFno nvarchar(20),#Dimension
nvarchar(30), #categoryid NVARCHAR(MAX) OUTPUT', #PartNo, #PPFno,#Dimension,
#categoryid OUTPUT
select #categoryid, #colname, #PartNo
That will effectively give you:
EXEC sp_executesql N'set #categoryid = (select distinct T1 from ProductProperty
where PartNo = #PartNo and PPFNo = #PPFno and DName = #Dimension)',
#PartNo nvarchar(20), #PPFno nvarchar(20),#Dimension
nvarchar(30), #categoryid NVARCHAR(MAX) OUTPUT', #PartNo, #PPFno,#Dimension,
#categoryid OUTPUT
I am sending a newsletter in SQL server using a cursor. All is working fine except the first email has no html.
Here is the stored procedure:.....
DECLARE
#html varchar(max)
SET #html = (SELECT html from NewsLetter where nLID=#nLID)
DECLARE crsEmailList CURSOR FOR
SELECT email, ListID from lists where category=#Category AND (DLC < DATEADD(DAY, -1,GETDATE()) OR DLC IS NULL)
OPEN crsEmailList
FETCH NEXT FROM crsEmailList INTO #email, #ListID
while ##FETCH_STATUS = 0
BEGIN
DECLARE #UniqueKey varchar(20),
#UnSubscribeURL varchar(200),
#ClickURL varchar(200)
SET #UnSubscribeURL='<a href=''http://.../userfiles/OHP/UnSubscribe.aspx?listID=' + convert(varchar, #ListID) + '''>Unsubscribe</a>'
SET #ClickURL='<a href=''http://.../userfiles/OHP/clicked.aspx?Key=' + convert(varchar, #UniqueKey ) + '&URL='
EXEC [register_system_email_audits] #ListID, #email, #Date, #UniqueKey output
SET #html = (SELECT html from NewsLetter where nLID=#nLID)
SET #html = Replace(#html,'[keyvalue]', #UniqueKey)
SET #html = Replace(#html,'<a href=\''',#ClickURL)
SET #html = Replace(#html,'[UnSubscribe]', #UnSubscribeURL )
SET #html = Replace(#html,'[date]', DATENAME(month, getdate()) )
EXEC msdb.dbo.sp_send_dbmail
#profile_Name ='Local Server',
#recipients= #email ,
#subject = #Subject,
#body = #html,
#body_format='HTML'
FETCH NEXT FROM crsEmailList INTO #email, #ListID
END
I have tried moving the line SET #html = (SELECT html from NewsLetter where nLID=#nLID) to different locations but no positive results.
One very likely explanation is that one of the parameters you are plugging into the html string is NULL for the first iteration.
When I run this code:
DECLARE #Str varchar(max) = 'Hello [test]';
DECLARE #test varchar(max) = NULL;
SET #Str = REPLACE(#Str, '[test]', #test);
PRINT #Str;
I don't get 'Hello ' as a result. I get nothing. So apparently using REPLACE to plug a NULL value into a string has the same effect as concatenating the string with NULL: which is, it makes the whole thing NULL.
Try using ISNULL on each of the variables in your REPLACE statements, and see if that doesn't fix the problem.
SET #html = Replace(#html,'[keyvalue]', ISNULL(#UniqueKey,''))
Or alternately, do the NULL-handling further upstream in the proc, but make sure you can't be trying to replace a token with NULL.
i need to send emails to approx, twenty recipients each day, i build a temp table with two columns
Email_Body
Email_address
there are at max 50 rows in the table each day
i want to loop though this table and execute sp_send_email
EXEC msdb.dbo.sp_send_dbmail
#Profile_name = 'DBA',
#recipients = #email_address,
#body = #Email_Body,
#subject = 'Test Email'
is there a way to do this without a cursor?
any links to an example would be appreciated, i have searched and can't find such an example. i am sure it is a very common process.
You might try the solution found here.
I think this code sample would help:
while (#count <=(select COUNT(*) from #table))
begin
select top 1 #Recepient_Email=Emp_Email,#mailBody=body from #table where ID=#count
EXEC msdb.dbo.sp_send_dbmail
#profile_name='Profile1',
#recipients=#Recepient_Email,
#subject = 'This is subject of test Email'
#body = #mailbody,
#body_format = 'HTML'
set #count =#count +1
END
--Email Campaign.
declare #HtmlModel varchar(max)
declare #HtmlBody varchar(max)
SELECT #HtmlModel = EmailBody
FROM EmailCampaigns
WHERE ID = 1
--a different process will have created an awesome looking well formed html with our known
--placeholders for [FirstName] [LastName] [Phone] [Email] that might ber substituted for individualization
--PRINT #HtmlModel;
SET #HtmlBody=''
declare
#mailID int,
#id int,
#first varchar(64),
#last varchar(64),
#phone varchar(64),
#email varchar(64)
declare c1 cursor for
--################################
SELECT ID,
ISNULL(FirstName,'Friend') AS FirstName,
ISNULL(LastName,'') AS LastName,
ISNULL(Phone,''),
ISNULL(Email ,'')
--the row_number is so that if i put your name in the database five times, you only get a single email.
FROM (
select ROW_NUMBER() over (partition by email order by email,len(firstname)desc,len(lastname)desc ) AS RW, *
from RawContacts
where email <> '') x
WHERE RW = 1
--this WHERe stays in place until we are ready to go LIVE with the email.
and email IN('lowell#somedomain.com','otherReviewer#somedomain.com')
--################################
open c1
fetch next from c1 into #id,#first,#last,#phone,#email
While ##fetch_status <> -1
begin
SET #HtmlBody = REPLACE(#HTMLModel,'[FirstName]',#first)
SET #HtmlBody = REPLACE(#HtmlBody,'[LastName]', #last)
SET #HtmlBody = REPLACE(#HtmlBody,'[Phone]', #phone)
SET #HtmlBody = REPLACE(#HtmlBody,'[Email]', #email)
--EXEC msdb.dbo.sp_send_dbmail
#Profile_name = 'Database Mail Profile Name',
#recipients=#email,
#subject = 'Our non profits Call for Volunteers',
#body = #HtmlBody,
#body_format = 'HTML',
#mailitem_id = #mailID OUTPUT
--#body_format = 'TEXT'
INSERT INTO CampaignRecipients(Campaign,RawContactID,MailSentID,MailSentDate)
SELECT 1,#id,#mailID,GETDATE()
fetch next from c1 into #id,#first,#last,#phone,#email
end
close c1
deallocate c1
GO