I am sending a HTML email that contains some rows from a table. I am using a temporary table #tableupdate which definitely has data in it when I run the script.
Everything runs fine and I get the email, it just has no content whatsoever. When I view the source of the email it's blank. Can anyone see where I have gone wrong?
To help diagnose the problem, I've been outputting the contents of the variable containing all the HTML in it at various points and it seems to be empty after this part:
select #tableHTML = #tableHTML + #body
+ '</table></div></body></html>'
#body doesn't seem to populate at all. I'm just not sure what to change to make it work.
The relevant piece of code, including comments to show where the data disappears:
select * from #tableupdate --rows are returned
declare #emailSubject varchar(100),
#textTitle varchar(100),
#tableHTML nvarchar(max)
select #textTitle = 'Test table'
set #tableHTML = '<html><head><style>' +
'td {border: solid black 1px;padding-left:5px;padding-right:5px;padding-top:1px;padding-bottom:1px;font-size:11pt;} ' +
'</style></head><body>'
+ '<div style="margin-top:20px; margin-left:5px; margin-bottom:15px; font-weight:bold; font-size:1.3em; font-family:tahoma;">' +
#textTitle + '</div>'
+ '<div style="margin-left:50px; font-family:tahoma;"><table cellpadding=0 cellspacing=0 border=0>' +
'<tr bgcolor=#4b6c9e>'
+ '<td align=center><font face="calibri" color=White><b>Col1</b></font></td>'
+ '<td align=center><font face="calibri" color=White><b>Col2</b></font></td>'
+ '<td align=center><font face="calibri" color=White><b>Col3</b></font></td>'
+ '<td align=center><font face="calibri" color=White><b>Col4</b></font></td>'
+ '<td align=center><font face="calibri" color=White><b>Col5</b></font></td>'
+
'</tr>'
select #tablehtml --has the correct value at this point
select #body =
(
select ROW_NUMBER() over(order by id) % 2 as TRRow,
td = col1,
td = col2,
td = col3,
td = col4,
td = col5
from #tableUpdate
where notificationType = 'NEWDATE'
order by clname
for XML raw('tr'), elements
)
select #body --empty?!
set #body = REPLACE(#body, '<td>', '<td align=center><font face="tahoma">')
set #body = REPLACE(#body, '</td>', '</font></td>')
set #body = REPLACE(#body, '_x0020_', space(1))
set #body = Replace(#body, '_x003D_', '=')
set #body = Replace(#body, '<tr><TRRow>0</TRRow>', '<tr bgcolor=#F8F8FD>')
set #body = Replace(#body, '<tr><TRRow>1</TRRow>', '<tr bgcolor=#EEEEF4>')
set #body = Replace(#body, '<TRRow>0</TRRow>', '')
select #body --still empty
select #tableHTML = #tableHTML + #body
+ '</table></div></body></html>'
select #tablehtml --now empty!
select #tableHTML = '<div style="color:Black; font-size:11pt; font-family:tahoma; width:100px;">' + #tableHTML + '</div>'
select #tableHTML --still empty
EXEC msdb.dbo.sp_send_dbmail
#profile_name = #databaseMailProfileName,
#body = #tableHTML,
#body_format ='HTML',
#recipients = 'me#me.com',
#subject = 'Subject' ;
If I simply pass select * from #tableupdate or similar to the email, it sends me the data in a not very nice format.
The issue is the query below, returns NULL.
select #body =
(
select ROW_NUMBER() over(order by id) % 2 as TRRow,
td = col1,
td = col2,
td = col3,
td = col4,
td = col5
from #tableUpdate
where notificationType = 'NEWDATE'
order by clname
for XML raw('tr'), elements
)
Focus on this single query, and you will solve your issue. Without sample data of #tableUpdate, we can't solve your problem. However, since #body is NULL, concatenating anything to it will also yield NULL.
For example, select 1 + null, 'this string' + null will return two NULLs.
Thus, all of these set operators will still yield NULL for #body
set #body = REPLACE(#body, '<td>', '<td align=center><font face="tahoma">')
set #body = REPLACE(#body, '</td>', '</font></td>')
set #body = REPLACE(#body, '_x0020_', space(1))
set #body = Replace(#body, '_x003D_', '=')
set #body = Replace(#body, '<tr><TRRow>0</TRRow>', '<tr bgcolor=#F8F8FD>')
set #body = Replace(#body, '<tr><TRRow>1</TRRow>', '<tr bgcolor=#EEEEF4>')
set #body = Replace(#body, '<TRRow>0</TRRow>', '')
select #body --still empty
Then, you set #tableHTML to NULL by concatenating it with #body because #body IS NULL
select #tableHTML = #tableHTML + #body
+ '</table></div></body></html>'
Which leaves #tableHTML and #body with the value of NULL.
A stab at fixing this, since you are building a table, would be to set #body like so:
select #body =
cast((select ROW_NUMBER() over(order by id) % 2 as 'td',
'',
isnull(col1,'') as 'td',
'',
isnull(col2,'') as 'td',
'',
isnull(col3,'') as 'td',
'',
isnull(col4,'') as 'td',
'',
isnull(col5,'') as 'td'
from #tableUpdate
where notificationType = 'NEWDATE'
order by clname
for XML path('tr'), elements) as nvarchar(max))
Related
I am trying to email data field containing URL. What am I doing wrong. Below is my code:
If I comment out the URL field [URL_Field] it works fine. Right now with the [URL_Field] the email sends but nothing comes through my email inbox.
DECLARE
#EmailSubject VARCHAR(100),
#TextTitle VARCHAR(100),
#TableHTML NVARCHAR(MAX),
#Body NVARCHAR(MAX),
#Profile_name VARCHAR(100) = 'TstDBMail',
#Recipients VARCHAR(2000) = 'name#company.com',
#startdate DATETIME,
#enddate DATETIME
SET #EmailSubject = 'ALERT: on'''+##SERVERNAME +''''
SET #TextTitle = 'Alert on ' + ##SERVERNAME +'.'
SET #TableHTML =
'<html>'+
'<head><style>'+
-- Data cells styles font size
'td {border:1px solid #ddd;padding-left:5px;padding-right:5px;padding-top:1px;padding-bottom:1px;font-size:10pt}'+
'</style></head>'+
'<body>'+
-- Text Title style
'<div style="margin-top:15px; margin-left:15px; margin-bottom:15px; font-weight:bold; font-size:13pt; font-family:calibri;">' + #TextTitle +'</div>' +
-- Color and columns names
'<div style="font-family:Calibri; "><table>'+'<tr bgcolor="red">'+
'<td align=left><font face="calibri" color=White><b>customer_id</b></font></td>'+
'<td align=left><font face="calibri" color=White><b>timestamp_utc</b></font></td>'+
'<td align=left><font face="calibri" color=White><b>URL_Field</b></font></td>'+
'</tr></div>'
-----------------------------------------------------------
----- Querying Data --------
-----------------------------------------------------------
SELECT #Body =(SELECT top 1
td = customer_id
,td = timestamp_utc
,td = URL_Field
FROM LAMN_Temp with (nolock)
FOR XML RAW('tr'), ELEMENTS)
SET #Body = REPLACE(#Body, '<td>', '<td align=left><font face="calibri">')
SET #TableHTML = #TableHTML + #Body + '</table></div></body></html>'
SET #TableHTML = '<div style="color:Black; font-size:8pt; font-family:Calibri; width:auto;">' + #TableHTML + '</div>'
-------------------------------
----- Sending email -----------
-------------------------------
IF(#Body IS NOT NULL)
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#Profile_name = #Profile_name,
#Recipients = #Recipients ,
#Body = #TableHTML,
#Subject = #EmailSubject,
#Body_format = 'HTML'
END;
NULL appended to any string value results in NULL, rather than appending an empty string. So if you have any missing values for the URL_Field, the entire #Body will end up as NULL. This fails the IF check and won't send email.
You can probably fix it by changing this:
,td = URL_Field
To this:
,td = coalesce(URL_Field,'')
This other way this might happen is if URL_Field adds enough size to the variable it overflows.
But I agree with the comment that this is a misuse of the SQL mail feature. You'll have much less pain and get much better results using a real mail processing service. It'll probably also cost less in the long run if you're properly accounting for your time spent maintaining this.
SET #tableHTML =
N'<H1>Report Heading</H1>' +
N'<table border="1">' +
N'<th>Check Number</th>' +
N'<th>Last Operator Date</th>' +
N'<th>Last Timestamp</th>' +
N'<th>Run Date</th>' +
N'<th>Issued Check Number</th>' +
N'<th>Error Description</th>' +
'<tr>' +
CAST ( ( SELECT td = S.CHK_NUM, '',
td = S.LAST_OPER_ID, '',
td = S.LAST_TIMESTMP, '',
td = S.RUN_DT, '',
td = ISNULL(S.RE_ISSUE_CHK_NUM,-1), '',
td = ISNULL(S.ERR_DESC,'<null>'), ''
FROM STAGNG_CDDP_ERR_RCD S
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;
PRINT #tableHTML
I want to count the resulting rows and assign it to a variable. How can that be achieved?
Just add a count query:
DECLARE #tableHTML NVARCHAR(MAX), #Count int;
SELECT #tableHTML =
N'<H1>Report Heading</H1>' +
N'<table border="1">' +
N'<th>Check Number</th>' +
N'<th>Last Operator Date</th>' +
N'<th>Last Timestamp</th>' +
N'<th>Run Date</th>' +
N'<th>Issued Check Number</th>' +
N'<th>Error Description</th>' +
'<tr>' +
CAST ( ( SELECT td = S.CHK_NUM, '',
td = S.LAST_OPER_ID, '',
td = S.LAST_TIMESTMP, '',
td = S.RUN_DT, '',
td = ISNULL(S.RE_ISSUE_CHK_NUM,-1), '',
td = ISNULL(S.ERR_DESC,'<null>'), ''
FROM STAGNG_CDDP_ERR_RCD S
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>'
, #Count = (SELECT COUNT(*) FROM STAGNG_CDDP_ERR_RCD);
PRINT #Count;
PRINT #tableHTML;
This is a follow-up question after a comment left on my last question/answer.
I have this code a HTML table but the first column has no name, which means the headings don't line up properly. This is because I'm using this syntax to identify even/odd rows - cast((select ROW_NUMBER() over(order by id) % 2 as 'td',
How can I set the heading for the first column?
set #tableHTML = '<html><head><style>' +
'td {border: solid black 1px;padding-left:5px;padding-right:5px;padding-top:1px;padding-bottom:1px;font-size:11pt;} ' +
'</style></head><body>'
+ '<div style="margin-top:20px; margin-left:5px; margin-bottom:15px; font-weight:bold; font-size:1.3em; font-family:tahoma;">' +
#textTitle + '</div>'
+ '<div style="margin-left:50px; font-family:tahoma;"><table cellpadding=0 cellspacing=0 border=0>' +
'<tr bgcolor=#4b6c9e>'
+ '<td align=center><font face="calibri" color=White><b>Col1</b></font></td>'
+ '<td align=center><font face="calibri" color=White><b>Col2</b></font></td>'
+ '<td align=center><font face="calibri" color=White><b>Col3</b></font></td>'
+ '<td align=center><font face="calibri" color=White><b>Col4</b></font></td>'
+ '<td align=center><font face="calibri" color=White><b>Col5</b></font></td>'
+
'</tr>'
select #body =
cast((select ROW_NUMBER() over(order by id) % 2 as 'td',
'',
isnull(col1,'') as 'td',
'',
isnull(col2,'') as 'td',
'',
isnull(col3,'') as 'td',
'',
isnull(col4,'') as 'td',
'',
isnull(col5,'') as 'td'
from #tableUpdate
where notificationType = 'NEWDATE'
order by clname
for XML path('tr'), elements) as nvarchar(max))
select #tableHTML = #tableHTML + #body
+ '</table></div></body></html>'
Your HTML is stronger than mine, but this should work and allow you to insert your styling where appropriate (if still needed).
select #body =
cast((select ROW_NUMBER() over(order by id) % 2 as 'td',
'',
isnull(col1,'') as 'td',
'',
isnull(col2,'') as 'td',
'',
isnull(col3,'') as 'td',
'',
isnull(col4,'') as 'td',
'',
isnull(col5,'') as 'td'
from #tableUpdate
where notificationType = 'NEWDATE'
order by clname
for XML path('tr'), elements) as nvarchar(max))
set #tableHTML = '<html>
<body>
<header>
<H3>This would be your header... maybey #textTitle information?</H3>
<P>Insert some stuff here if you want</P>
</header>
<table border = 1>
<tr>
<th>IDCol</th>
<th>Col1</th>
<th>Col2</th>
<th>Col3/th>
<th>Col4</th>
<th>Col5</th>
</tr>'
select #tableHTML = #tableHTML + isnull(#body,'') + '</table></body></html>'
I am using SQL+HTML script to send an email containing top 5 columns of a table mytable. Currently, I have all the column titles aligned centrally and each column entries aligned to the right using [th] and [td] repsectively. How can I make entries in Vendor column left aligned while keeping everything else the same?
DECLARE #dt datetime, #prev_dt datetime
SELECT #dt = dbo.GetDateOnly(getdate())
SELECT #prev_dt = dbo.GetDateOnly(getdate()-1)
SELECT top 5
Vendor,
OUTL_New_$,
OUTL_Old_$,
Outl_Diff_$ ,
OUTL_Diff_Perc,
Analyst
into #vpositive
FROM mytable
ORDER BY 4 DESC
--select * from #vpositive
if(##ROWCOUNT>0)
begin
--drop table #email
DECLARE #Body2 varchar(max)
declare #TableHead2 varchar(max)
declare #TableTail varchar(max)
Set #TableTail = '</table></body></html>';
Set #TableHead2 = '<html><head>' +
'<hr style="height:1px;border:none;color:#333;background-color:#333;">'+
'<H5 style="color: #000000; font-family:Arial">2: VENDOR LEVEL TOP 5 OUTL $ <font color="blue">INCREMENTS -</font></H5>' +
'<style>' +
'td {border: solid black 1px;padding-left:5px;padding-right:5px;padding-top:1px;padding-bottom:1px;font-size:10pt;color:Black;text-align:right;font-family:Arial;} ' +
'th {border: solid black 1px;padding-left:5px;padding-right:5px;padding-top:1px;padding-bottom:1px;font-size:10pt;color:Black;text-align:center;font-family:Arial;} ' +
'</style>' +
'</head>' +
'<body><table cellpadding=0 cellspacing=0 border=0 width=auto>' +
'<tr bgcolor=#007336>'+
'<th><b><font color="white">Vendor</font></b></th>' +
'<th><b><font color="white">OUTL$ New</font></b></th>' +
'<th><b><font color="white">OUTL$ Old</font></b></th>' +
'<th><b><font color="white">OUTL$ Diff</font></b></th>' +
'<th><b><font color="white">OUTL$ Diff Perc</font></b></th>' +
'<th><b><font color="white">Analyst</font></b></th></tr>';
--Select information for the Report--
Select #Body2= (select
substring(Vendor,1,60) As [TD]
,'$ '+substring(parsename(convert(varchar,convert(money,cast(OUTL_New_$ as int)),1),2),1,13) As [TD]
,'$ '+substring(parsename(convert(varchar,convert(money,cast(OUTL_Old_$ as int)),1),2),1,13) As [TD]
,'$ '+substring(parsename(convert(varchar,convert(money,cast(OUTL_Diff_$ as int)),1),2),1,13) As [TD]
,substring(CAST(OUTL_Diff_Perc AS varchar(10)),1,4)+' %' As [TD]
,substring(Analyst,1,20) As [TD]
from #vpositive
For XML raw('tr'), Elements)
Set #Body = #TableHead2 + #Body2 + #TableTail
--Email
EXEC msdb.dbo.sp_send_dbmail
#recipients='abc#abc.com',
#subject = My analysis',
#body = #Body,
#body_format = 'HTML';
end
Did you try this:
<th align="left">
or this:
text-align: left;
I'm having a problem sending a HTML formatted email from SQL server.
With the following section of code I get a "Line 1, incorrect syntax near '<'" error.
SET #tableHTML =
'<H1>Progress Report</H1>' +
'<table border="1">' +
'<tr>' +
'<th>Project Name</th>' +
'<th>Platform</th>' +
'<th>Due By</th>' +
'<th>Current Status</th>' +
'<th>Current State</th>' +
'</tr>' +
CAST (
(
SELECT
td = [Project Name], ' ',
td = Platform, ' ',
td = [Due By], ' ',
td = [Current Status], ' ',
td = [Current State], ' '
FROM [dbo].[table_name]
ORDER BY [Current Status] DESC
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
'</table>' ;
I cant seem to pin it to anything in particular? Any Idea's?
Thanks
Update 1:
Ok I've run the code in a debug session and have checked the contents of #tableHTML, the contents looks fine and it gets populated with the expected data from my Table.
Meaning the errors coming in from somewhere else, so I've copied the whole query this time.
DECLARE #tableHTML NVARCHAR(MAX);
SET #tableHTML =
'<h1>Progress Report</h1>' +
'<table border="1">' +
'<tr>' +
'<th>Project Name</th>' +
'<th>Platform</th>' +
'<th>Due By</th>' +
'<th>Current Status</th>' +
'<th>Current State</th>' +
'</tr>' +
CAST
(
(
SELECT
td = [Project Name], '',
td = Platform, '',
td = [Due By], '',
td = [Current Status], '',
td = [Current State], ''
FROM [dbo].[table_name]
ORDER BY [Current Status] DESC
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
'</table>';
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'db_mail_account',
#recipients = 'example#example.com',
#subject = 'Daily Project Tracking Report',
#query = #tableHTML,
#body_format = 'HTML';
Thanks again.
It looks like you want #tableHTML to be the body of the email, but you're passing it in as #query, which has to contain valid SQL, hence the error.
Try using #body instead:
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'db_mail_account',
#recipients = 'example#example.com',
#subject = 'Daily Project Tracking Report',
#body = #tableHTML,
#body_format = 'HTML';