Send email in a tabular format using SQL Server database mail - sql

I have created SSIS package which has 1 SQL task (stored procedure which returns list of below 4 columns. How will achieve the following table to be sent through email. Immediate Next task here what I would do is create another stored procdure which accepts the result set from 1st stored proc through another Sql task and 2nd stored proc contains msdb_SendDBemail call . Is there any better approach

Nice thread on stack exchange: Need to Send a formatted HTML Email via Database Mail in Sql Server 2008 R2
It has an answer with a code of stored procedure dbo.HtmlTable that can generate HTML for further use in database mail:
CREATE table ##foo (bar1 int, bar2 varchar(20), bar3 datetime)
INSERT into ##foo values (1, 'Abcdef', getdate())
INSERT into ##foo values (2, 'Ghijkl', '05/05/15')
DECLARE #tableHtml varchar(max)
EXEC dbo.HtmlTable
'##foo',
#tableHtml output
PRINT #tableHtml
#tableHtml will contain html that renders into:

You can try something like this to get data in tabular format. To execute row by row you need to implement a cursor like this.
CREATE PROCEDURE [dbo].[SendNewDeviceInfoToEmployee]
AS
BEGIN
SET NOCOUNT ON
DECLARE #Mbody VARCHAR(MAX),
#Sub VARCHAR(500),
#EmpEmailPwdId BIGINT,
#Emp_nm VARCHAR(150),
#ToEmailid VARCHAR(150),
#NewEmailId VARCHAR(150),
DECLARE #Recipients VARCHAR(max)
DECLARE SendautoLoginDtl CURSOR FOR
SELECT EmpEmailPwdId, EmpName, ToEmailid, NewEmailId, EmpPassword
FROM EmployeeEmailIdPassword WHERE ISNULL(Freeze,'N') = 'N' AND ISNULL(IsMailSent,'N') = 'N' AND ISNULL(ToEmailId,'') <> '' AND ISNULL(NewEmailId,'') <> ''
ORDER BY EmpEmailPwdId
OPEN SendautoLoginDtl;
FETCH NEXT FROM SendautoLoginDtl INTO #EmpEmailPwdId, #emp_nm, #ToEmailid, #NewEmailId
WHILE( ##FETCH_STATUS = 0 )
BEGIN
SET #xml = CAST(( SELECT [Rank] AS 'td','',[Player Name] AS 'td','', [Ranking Points] AS 'td','', Country AS 'td'
FROM #Temp
ORDER BY Rank
FOR XML PATH('tr'), ELEMENTS ) AS NVARCHAR(MAX))
SET #Mbody =N'<html><body><H3>Tennis Rankings Info</H3>
<table border = 1>
<tr>
<th> Rank </th> <th> Player Name </th> <th> Ranking Points </th> <th> Country </th></tr>'
SET #body = #body + #xml +'</table></body></html>'
SET #sub='Your New Device Details - ' + #emp_nm
set #Recipients = #ToEmailid
EXEC msdb.dbo.sp_send_dbmail '<YourDBMailProfileName>' ,
#recipients = #Recipients ,
#copy_recipients = #NewEmailId,
#subject = #sub ,
#body = #Mbody ,
#body_format = 'HTML'
--Update table if required
UPDATE <YourTable>
SET IsMailSent = 'Y'
WHERE EmpEmailPwdId = #EmpEmailPwdId
FETCH NEXT FROM SendautoLoginDtl INTO #EmpEmailPwdId, #emp_nm, #ToEmailid, #NewEmailId, #EmpPassword
END
CLOSE SendautoLoginDtl;
DEALLOCATE SendautoLoginDtl;
END
You can learn about cursor here.

Related

stored procedure not running, maybe bad job configuration

i have a stored procedure, on a sql server, with the following code:
USE [MASS]
GO
/****** Object: StoredProcedure [dbo].[DossierEmailSend] Script Date: 05/11/2019 17:36:13 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[DossierEmailSend]
AS
--Create a holding table for the dossiers that met the criteria
DECLARE #dossiers TABLE (col1 varchar(100), col2 varchar(100), col3 varchar(100), col4 varchar(100));
--Insert the dossiers that met the criteria
INSERT INTO #dossiers
SELECT no, nome, obrano, convert(varchar,datafinal) col4
FROM bo
WHERE nmdos LIKE '%preço%'
AND datafinal = DATEADD(day, -1, CONVERT(date, GETDATE()))
--Create a row check to determine whether to send the email or not
DECLARE #rows int;
SET #rows = (SELECT COUNT(*) FROM #dossiers)
--Set the body elements
DECLARE #message varchar(1000);
-- declare the xml data to pass to the HTML body
DECLARE #xml NVARCHAR(MAX);
-- body will hold the HTML formatted table in the email
DECLARE #body NVARCHAR(MAX);
--Create the columns that will hold each row of data as xml
SET #xml = CAST(( SELECT col1 AS 'td','',col2 AS 'td','', col3 AS 'td','', col4 AS 'td'
FROM #dossiers
FOR XML PATH('tr'), ELEMENTS ) AS NVARCHAR(MAX))
--Set the HTML for the body
SET #body ='<html><body><H3>Dossier Info</H3>
<table border = 1>
<tr>
<th> Num </th> <th> Nome </th> <th> Dossier </th> <th> Data de Fecho </th></tr>'
--Stitch everything together, appending the HTML table
SET #body = #body + #xml +'</table></body></html>'
SET NOCOUNT ON
--Check if any dossiers met the criteria
IF #rows > 0
BEGIN
--Send the email and append the data table to the body
EXEC dbo.uspSendEmail 'Encerramento Dossier Preços', 'ssantos#mass.pt', #body, NULL, 'filipeferreira#mass.pt'
SET NOCOUNT OFF
END
to run this procedure, i created a job, that fetches this procedure, but the fact is that it's not running. on the job properties, i have set:
on success action quit the job reporting success and on failure action the same thing. i really don't know if the mistake is here, any thoughts on this guys?

Unable to develop body for email in SQL

I have written a stored procedure where "i have to compare values in two tables and send mail to the users which are not present in second table.
I have to automate this report .
But issue comes when i am trying to make mail body for the same.
The mail body is to be taken from table record ie column name REQ_Approval_EMAILBODY.Also the Recipient id has to be taken from table records ie cloumn name REQ_Approval_EMAILID.
This query has to execute for all the records one by one with respective email ID from table.
Please help me to sort out his.
Thanks in advance
CREATE PROCEDURE Email_Daily
AS
BEGIN
DECLARE #bodynew VARCHAR(Max)
DECLARE #query1 VARCHAR(Max)
DECLARE #Para VARCHAR(Max)
DECLARE #query2 VARCHAR(Max)
DECLARE #query3 VARCHAR(Max)
DECLARE #query5 VARCHAR(Max)
DECLARE #Yesterday VARCHAR(50)
SET #Yesterday = REPLACE(CONVERT(varchar(50),GETDATE()-1,102),'.','-')
DECLARE #TODAY_DDMMYYY VARCHAR(50)
SET #TODAY_DDMMYYY = REPLACE(CONVERT(varchar(50),GETDATE()-1,6),' ','-')
SELECT * into #Temp3_New_Table
FROM(
SELECT [MessageIdentifier]
,[MessageIdentifier_Archive]
,CONVERT(DATE,REQ_SentDate) AS REQ_SentDate
,[REQ_Token]
,[REQ_Approval_Number]
,[REQ_Order_Number]
,[REQ_Document_Number]
,[REQ_Approval_EMAILID]
,[REQ_Approval_EMAILBODY]
,[REQ_Approval_EMAIL_Subject]
,[RES_Date]
,[IsValid]
,[Response_MessageIdentifier]
,[ReSubmit_Count]
,'0' as Flag
FROM [SAEI].[dbo].[Approval_EMAIL_LOG]
where CONVERT(DATE,REQ_SentDate) = #Yesterday
and res_date is null
and req_approval_number+req_order_number+req_document_number not in
(SELECT
[RES_Approval_Number]+[RES_Order_Number]+[RES_Document_Number]
FROM [SAEI].[dbo].[Approval_Response_WEB_LOG]))as Tr
set #query5='select * from #Temp3_New_Table'
set #para='<p style="font-family:arial; font-size:14px">
Dear Team,
</br>
</br>
</br>
</p>'
Set #bodynew = #PARA
DECLARE #subjects VARCHAR(200)
DECLARE #FileAttachment VARCHAR(400)
DECLARE #Recipients VARCHAR(MAX)
DECLARE #copy VARCHAR(MAX)
set #Recipients='select [REQ_Approval_EMAILID] from #Temp3_New_Table'
drop table #Temp3_New_Table
End
try this
select #para = concat('<p style="font-family:arial; font-size:14px">Dear Team,</br></br>', [REQ_Approval_EMAILBODY],'</br></p>')
from #Temp3_New_Table
{where condition}
EDIT
if you want a cursor then you can try this
DECLARE evilCurse CURSOR FOR
SELECT [REQ_Approval_EMAILID]
,[REQ_Approval_EMAILBODY] = concat('<p style="font-family:arial; font-size:14px">Dear Team,</br></br>', [REQ_Approval_EMAILBODY],'</br></p>')
,[REQ_Approval_EMAIL_Subject]
FROM [SAEI].[dbo].[Approval_EMAIL_LOG]
where CONVERT(DATE,REQ_SentDate) = #Yesterday
and res_date is null
and req_approval_number+req_order_number+req_document_number not in
(SELECT [RES_Approval_Number]+[RES_Order_Number]+[RES_Document_Number]
FROM [SAEI].[dbo].[Approval_Response_WEB_LOG])
OPEN evilCurse
FETCH NEXT FROM evilCurse
INTO #Recipients, #bodynew, #subjects
WHILE ##FETCH_STATUS = 0
BEGIN
--do what ever you want to do to here
FETCH NEXT FROM evilCurse
INTO #Recipients, #bodynew, #subjects
END
CLOSE evilCurse;
DEALLOCATE evilCurse;

SQL Server email queue

I have an orders table which is populated with new orders frequently
Orders table:
OrderID OrderName EmailAddress Status
-----------------------------------------------------
1 iphone test#gmail.co.uk New
2 samsung nw#gmail.com New
3 nexus f#gmail.com Approved
For every order line which has status = 'New', I would like to set up a job to run every 30 minutes send an email to those recipients.
As per my understanding, you need to schedule a job which send an email notification if order status is 'New'.
If so create the following stored procedure
CREATE PROCEDURE NewOrders_Job
AS
BEGIN
DECLARE #OrderName varchar(200), #EmailAddress varchar(200)
SELECT
#OrderName = ' You have a sale for '+[OrderName]+', at +'CONVERT(VARCHAR(10),GETDATE(),)'+'
,#EmailAddress = [EmailAddress]
FROM [Orders table]
WHERE
[Status] = 'New'
IF(ISNULL(#EmailAddress,'')<>'')
BEGIN
--mail
DECLARE
#profile_name VARCHAR(200)
,#recipients VARCHAR(MAX)
,#copy_recipients VARCHAR(MAX)
,#blind_copy_recipients VARCHAR(MAX)
,#body VARCHAR(MAX)
,#body_format VARCHAR(MAX)
,#subject VARCHAR(MAX)
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'Your_Profile_Name'
,#recipients = #EmailAddress
,#copy_recipients = 'youremail#domain.com'
,#blind_copy_recipients = 'admin#yourdomain.com'
,#body = #OrderName
,#body_format = 'HTML'
,#subject = 'You have a new sales Order';
END
END
now, create a new job which run's for 30 mins with above stored procedure

procedure that returns varchar

I tried to make a function that returns varchar, but I can't because I'm using CREATE TABLE inside, and when I'm creating it with a procedure I can't return a value.
I wanted to know if you have some advice.
I made this just to make a string with emails separated by ";" so I can have all the "manager" mails in one varchar (for the recipients).
ALTER procedure [dbo].[Manager_email]
AS
BEGIN
declare #mails varchar (max),
#number_of_mails int,
#counter int
set #counter=2
create table #temp ( id int identity, email varchar(30))
insert into #temp (email)
select Email
from hr.Employees
where lower (EmpRole) like 'manager'
set #number_of_mails=##ROWCOUNT
set #mails = (select email from #temp where id =1 ) + ';'
while #counter <= #number_of_mails
BEGIN
set #mails = #mails + (select email from #temp where id =#counter ) + ';'
set #counter = #counter+1
END
drop table #temp
return cast (#mails as varchar (200))
END
You can only return integer value back from the procedure, If you want to return varchar value from procedure its good to make use of output variable in procedure.
Example
CREATE PROCEDURE Sales.uspGetEmployeeSalesYTD
#SalesPerson nvarchar(50),
#SalesYTD money OUTPUT
AS
SET NOCOUNT ON;
SELECT #SalesYTD = SalesYTD
FROM Sales.SalesPerson AS sp
JOIN HumanResources.vEmployee AS e ON e.BusinessEntityID = sp.BusinessEntityID
WHERE LastName = #SalesPerson;
RETURN
like in above procedure return #SalesYTD from procedure.
you can check full post on MSDN : Returning Data by Using OUTPUT Parameters
You can use function instead
CREATE FUNCTION Manager_email ()
RETURNS varchar(max)
AS
BEGIN
declare #email varchar(30)
declare #emails varchar(max)
set #emails = ''
declare cur cursor for
select Email
from hr.Employees
where lower (EmpRole) like 'manager'
open cur
fetch next from cur into #email
while ##fetch_status = 0
begin
set #emails = #emails + #email + ';'
fetch next from cur into #email
end
close cur
deallocate cur
return #emails
END
You can use table variable instead of temporary table. In that case you can continue to use UDF.

Send Data Via Email in T-SQL

I am writing a stored procedure which collects all changes that were happend in a table for a given date and would like to send recordset to an administrator via email from SQL Batch Job.
Now untill now, I couldn't figure out is how to send recordset in an email body. Is it possible to construct email body based on the recordset obtained from some tsql logic.
Any help is appriciated
Thanks
TheITGuy
Look into the sp_send_dbmail procedure, which allows you to execute a query and send the results in the e-mail body or as a file attachment.
This might provide you some impetus:
CREATE TABLE #Temp
(
[Rank] [int],
[Player Name] [varchar](128),
[Ranking Points] [int],
[Country] [varchar](128)
)
INSERT INTO #Temp
SELECT 1,'Rafael Nadal',12390,'Spain'
UNION ALL
SELECT 2,'Roger Federer',7965,'Switzerland'
UNION ALL
SELECT 3,'Novak Djokovic',7880,'Serbia'
DECLARE #xml NVARCHAR(MAX)
DECLARE #body NVARCHAR(MAX)
SET #xml = CAST(( SELECT [Rank] AS 'td','',[Player Name] AS 'td','',
[Ranking Points] AS 'td','', Country AS 'td'
FROM #Temp ORDER BY Rank
FOR XML PATH('tr'), ELEMENTS ) AS NVARCHAR(MAX))
SET #body ='<html><body><H3>Tennis Rankings Info</H3>
<table border = 1>
<tr>
<th> Rank </th> <th> Player Name </th> <th> Ranking Points </th> <th> Country </th></tr>'
SET #body = #body + #xml +'</table></body></html>'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'SQL ALERTING', -- replace with your SQL Database Mail Profile
#body = #body,
#body_format ='HTML',
#recipients = 'bruhaspathy#hotmail.com', -- replace with your email address
#subject = 'E-mail in Tabular Format' ;
DROP TABLE #Temp
The firm I work for requires the name/value pair to be on separate lines rather than in a table. While my solution could use some tuning, after much work, I came up with a solution with css formatting. I can't figure out why, however, the width of the NAME column isn't 100px, as I have requested.
The special characters are < alt >+0182, < alt >+0183 and < alt >+0185, respectively.
I will continue to strive for a more elegant solution without so many replace functions but the firm is more concerned with a 'now' solution than an elegant one. Feedback/improvements would be appreciated.
The email arrives (in Outlook) formatted as such, which is our firm's preference:
Tennis Rankings Info
Rank: 1
Player Name: Rafael Nadal
Points: 12390
Country: Spain
Rank: 2
Player Name: Roger Federer
Points: 7965
Country: Switzerland
Rank: 3
Player Name: Novak Djokovic
Points: 7880
Country: Serbia
Here is my solution:
CREATE TABLE #Temp
(
[Rank] [int],
[Player Name] [varchar](128),
[Ranking Points] [int],
[Country] [varchar](128)
)
INSERT INTO #Temp
SELECT 1,'Rafael Nadal',12390,'Spain'
UNION ALL
SELECT 2,'Roger Federer',7965,'Switzerland'
UNION ALL
SELECT 3,'Novak Djokovic',7880,'Serbia'
DECLARE #xml NVARCHAR(MAX)
DECLARE #body NVARCHAR(MAX)
SET #xml = CAST(( SELECT '¶Rank:·º' + convert(varchar, [Rank]) AS 'br','','¶Player Name:·º' +[Player Name] AS 'br','',
'¶Points:·º' + convert(varchar, [Ranking Points]) AS 'br','', '¶Country:·º' + Country AS 'br'
FROM #Temp ORDER BY Rank
FOR XML PATH('br'), ELEMENTS ) AS NVARCHAR(MAX))
SET #body ='<html><head><style type=''text/css''>body{font-family:tahoma;font-size:9pt;}.h{width:100px;}</style></head><body><H3>Tennis Rankings Info</H3>'
SET #body = #body + #xml +'</body></html>'
set #body = replace(#body, '</br>', '<br />')
set #body = replace(#body, '<br><br>', '<p>')
set #body = replace(#body, '<br>', '')
set #body = replace(#body, '<br /><br />', '</p>')
set #body = replace(#body, '¶', '<span class=''h''>')
set #body = replace(#body, '·', '</span>')
set #body = replace(#body, 'º', ' ')
--select #body
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'DBMail', -- replace with your SQL Database Mail Profile
#body = #body,
#body_format ='HTML',
#recipients = 'xxx#xxx.com', -- replace with your email address
#subject = 'E-mail in Tabular Format' ;
DROP TABLE #Temp