Calling sp_send_dbmail from a sproc within an execution context - sql-server

Using SQL-Server 2019; I am trying to use sp_send_dbmail and have successfully sent test emails from SQL-Server so believe the configuration is fine.
A sproc runs in the execution context of a SQL-Login, which updates some tables in a database and then calls the sproc below which is supposed to send emails via msdb.dbo.sp_send_dbmail.
CREATE PROCEDURE [dbo].[sp_SendEmail]
#emailAddress AS NVARCHAR(MAX),
#emailBody AS NVARCHAR(MAX),
#emailSubject AS NVARCHAR(150),
#attachmentPath AS NVARCHAR(255) = NULL,
#emailId AS INT OUTPUT
WITH EXECUTE AS N'Bob'
AS
BEGIN
SET NOCOUNT ON;
DECLARE #bSuccess AS INT = 0;
EXECUTE #bSuccess = [msdb].[dbo].[sp_send_dbmail]
#profile_name = N'Profile',
#recipients = #emailAddress,
#subject = #emailSubject,
#body = #emailBody,
#body_format = N'HTML',
#importance = N'High',
#file_attachments = #attachmentPath,
#mailitem_id = #emailId OUTPUT;
RETURN #bSuccess;
END
GO
When I run the sproc I get the error:
Msg 229, Level 14, State 5, Procedure msdb.dbo.sp_send_dbmail, Line 1
[Batch Start Line 2] The EXECUTE permission was denied on the object
'sp_send_dbmail', database 'msdb', schema 'dbo'.
The SQL-Login, Bob, has a user mapping to the msdb database using the default schema and is a member of the DatabaseMailUserRole role.
I've given Bob execute permission on the sp_send_dbmail securable, which seems like a duplication of what the DatabaseMailUserRole provides, but still get the error above.
I'd appreciate any insight you can throw at me.

Related

Send email via SQL Server Agent, based on the result of a T-SQL stored procedure

I have a T-SQL stored procedure (which returns a single scalar value called #HourDifference as an output parameter); you can see the execution below:
DECLARE #HourDifference_output TINYINT;
-- I declare a variable to capture the output parameter--
EXEC dbo.sproc_XYZ_Notification
#HourDifference = #HourDifference_output OUTPUT;
SELECT #HourDifference_output AS HourDifferenceCaptured
I have the below requirements:
If HourDifferenceCaptured > 12, I will need to send a email
If HourDifferenceCaptured <= 12, no email needs to be sent; nothing needs to be done.
I need to have two schedules, one at 7 AM, the other at 7 PM in the SQL Server Agent.
Can someone provide the code and guide me through this process?
You could create an SQL Server agent job, with a t-sql step which uses msdb.dbo.sp_send_dbmail for sending an e-mail, when required (please see here, for the stored procedure complete reference).
Try something similar to the following:
DECLARE #HourDifference_output TINYINT;
EXEC dbo.sproc_XYZ_Notification #HourDifference_output OUTPUT;
-- SELECT #HourDifference_output AS HourDifferenceCaptured
IF #HourDifference_output > 12
BEGIN
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'db_mail_profile_i_have_already_created',
#recipients = 'intended-recipients#yourorganization.com',
#body = 'Too many hours difference.',
#subject = 'Automated Message' ;
END
You must have already configured a database mail account, a database mail profile and granted appropriate access to the user running the job step. The second link also contains sample scripts for creating a database mail account and profile, adding the account to the profile and granting access appropriately (I personally prefer to configure database mail via the SSMS db mail wizard).
A decision to be made is whether to create a public or a private profile. You can find more information about the differences here.
Finally, it is, in my opinion, good practice to notify an administrator (via SQL Server Agent build-in mechanisms) when a job / step fails.
USE <database_name>
GO
DECLARE #subject NVARCHAR(max) = 'Email subject'
, #body NVARCHAR(MAX)
DECLARE #HourDifference_output TINYINT;
EXEC dbo.sproc_XYZ_Notification #HourDifference = #HourDifference_output OUTPUT;
SELECT #HourDifference_output AS HourDifferenceCaptured
IF (#HourDifference_output> 12)
BEGIN
SET #body = '<!DOCTYPE html>
<html>
<body>
<body style="color:black; font-family:Times New Roman; font-size:14x"> .......... body text ......... </body>
<body style="color:SlateGray; font-family:Times New Roman; font-size:14px;line-height: 1;"> ------------------------------------------------------------------' + '
<body style="color:SlateGray; font-family:Times New Roman; font-size:14px;line-height: 1;"> ------------------------------------------------------------------' + '
</body>
</HTML>'
EXEC msdb.dbo.sp_send_dbmail #profile_name = 'Profile name'
, #recipients = 'distibution email'
, #body = #body
, #body_format = 'HTML'
, #subject = #subject
END
GO

Error with automated mail

I'm working on a piece of code that will email me the results of some queries twice a day from SQL Server 2016. When I run this bit of code from my developer window, it works fine. When I run it from the job, I get this error:
Executed as user: myDB\svcAGCRM2016_PRD. Failed to initialize sqlcmd
library with error number -2147467259. [SQLSTATE 42000] (Error 22050).
The step failed.
This is the code that runs:
declare #recipient_name varchar(500)
declare #SqlQuery varchar(max)
SET #SqlQuery='exec [myDB].[dbo].[sp_DailyRejectionRate]'
set #recipient_name = 'myemail#email.com'
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'SMTPProfile',
#recipients =#recipient_name,
#subject = '[INFO]'
,#query='exec [myDB].[dbo].[sp_DailyRejectionRate];
I'm running this from a service account. Weirdly, not with the name of the service account in the error. Actually, I can't even find that account.
In the code, I'm doing an exec because otherwise the query is too long for query.
The service account that runs this is an SA. Also, I wrote another query this morning that sends out email with not problems today.
Any ideas?
What if you explicitly specify the user in the query string?
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'SMTPProfile',
#recipients =#recipient_name,
#subject = '[INFO]'
,#query='execute as user='my_sa_user' exec [myDB].[dbo].[sp_DailyRejectionRate];

How can I create an alert in SQL Server?

I have the following structure:
cho_id int
cho_nombre varchar(200)
cho_documento varchar(15)
cho_dirrecion varchar(100)
cho_telefono varchar(15)
cho_fec_vencimiento_lic datetime
cho_categoria int
est_id int
I have a row of datetime type and I want that every time the date approaches send me an alert 15 days before and send me by email.
How can I design this in SQL Server? Does it have to be with stored procedures? Triggers?
Here's a quick shell you can use for a procedure, which you'll then schedule as a job to run daily. You can change the logic of the IF as you seem fit.
create procedure myProc
as
if (select datediff(day,max(cho_fec_vencimiento_lic),getdate()) from SomeTable) = 15
begin
exec msdb.dbo.sp_send_dbmail
#profile_name = null,
#recipients = 'email#domain.org',
#body = 'This is your email alert',
#body_format = 'TEXT',
#subject = 'Alert'
end
go
sp_dend_dbmail reference
Schedule a job reference

sqlcmd library error in sp_send_dbmail

I am using sp_send_dbmail to send an email containing entries in table Persons. It throws following error -
Failed to initialize sqlcmd library with error number -2147467259.
My query is below -
declare #q varchar(max)
SET #q='SELECT FirstName,LastName FROM dw_extract.dbo.Persons'
USE msdb
EXEC sp_send_dbmail
#profile_name = 'profile_name',
#recipients = 'abc#xyz.com',
#subject = 'T-SQL Query Result',
#body = 'The result from SELECT is appended below',
#execute_query_database = 'dw_extract',
#query = #q
I did some research and found that few people who faced such problem could get rid of it by explicitly stating column names and database of the table used. I did that but still it continues to throw the error.

Permissions to set job Enable/Disable in SQL Server

The database user has been granted SQLAgentOperatorRole, but there are still error when set job enable/disable. The error message is:
SELECT permission was denied on the object 'sysjobs', database 'msdb', schema 'dbo'
We set the job enable/disable by sp_update_job.
Comments:
When executing the following statement, will get the error.
bool result = ObjectInstance.ExecuteStoreQuery<bool>("EXEC usp_prod_SetJobStatus #jobName={0}, #isEnable={1}", jobName, isEnable).FirstOrDefault();
But, while use the following statement, it will execute successful.
ObjectInstance.ExecuteStoreCommand("EXEC msdb.dbo.sp_update_job #job_name={0}, #enabled={1}", jobName, isEnable);
usp_prod_SetJobStatus SP:
CREATE PROCEDURE [dbo].[usp_prod_SetJobStatus]
#jobName VARCHAR(200),
#isEnable BIT
AS
BEGIN
DECLARE #jobId uniqueidentifier
DECLARE #result BIT
SELECT #jobId = job_id FROM msdb.dbo.sysjobs WHERE name = #jobName
IF(#jobId IS NOT NULL)
BEGIN
EXEC #result = msdb.dbo.sp_update_job #job_name=#jobName, #enabled=#isEnable
END
ELSE
BEGIN
SET #result = 1
END
SELECT #result
END
I have solved this problem. The reason is that there is no SELECT permission on sysjobs table for the user. So, we need to grant the SELECT perssion for the user.
USE msdb
GRANT SELECT ON msdb.dbo.sysjobs TO useName
You have given agent operator role its having enable and disable but SQLAgentOperatorRole members can enable or disable local jobs they do not own by using the stored procedure sp_update_job and specifying values for the #enabled and the #job_id (or #job_name) parameters. If a member of this role specifies any other parameters for this stored procedure, execution of the procedure will fail ..You have to execute permissions on sql server agnet .

Resources