• One way to hack around this problem is to turn TRUSTWORTHY ON for the database that has your wrapper stored procedure in it. However, the best way to do this is to use EXECUTE AS OWNER, and sign the procedure with a Certificate. To do this requires the following steps:

    First create the stored procedure.

    Then create a certificate in the database with a strong password.

    Backup the certificate to disk.

    Restore the certificate in master and create a login from the certificate.

    Grant Authenticate Server to the login.

    Add a database user in msdb for the certificate login.

    Then add the DatabaseMailUserRole to the msdb user for the certificate login.

    Finally sign the stored procedure in your database with the certificate.

    A full repro for this is below:

    CREATE DATABASE TestDBMail

    GO

    USE [TestDBMail]

    GO

    CREATE PROCEDURE [dbo].[TestSendMail]

    (

    @To NVARCHAR(1000),

    @Subject NVARCHAR(100),

    @Body NVARCHAR(MAX)

    )

    WITH EXECUTE AS OWNER

    AS

    BEGIN

    EXEC msdb.dbo.sp_send_dbmail

    @profile_name = N'Database Mail Profile',

    @recipients = @To,

    @subject = @Subject,

    @body = @Body

    END

    GO

    -- This should fail

    EXECUTE [dbo].[TestSendMail] 'someemail@domain.com', 'test', 'body'

    -- Create a certificate to sign stored procedures with

    CREATE CERTIFICATE [DBMailCertificate]

    ENCRYPTION BY PASSWORD = '$tr0ngp@$$w0rd'

    WITH SUBJECT = 'Certificate for signing TestSendMail Stored Procedure';

    GO

    -- Backup certificate so it can be create in master database

    BACKUP CERTIFICATE [DBMailCertificate]

    TO FILE = 'd:\Backup\DBMailCertificate.CER';

    GO

    -- Add Certificate to Master Database

    USE [master]

    GO

    CREATE CERTIFICATE [DBMailCertificate]

    FROM FILE = 'd:\Backup\DBMailCertificate.CER';

    GO

    -- Create a login from the certificate

    CREATE LOGIN [DBMailLogin]

    FROM CERTIFICATE [DBMailCertificate];

    GO

    -- The Login must have Authenticate Sever to access server scoped system tables

    -- per http://msdn.microsoft.com/en-us/library/ms190785.aspx

    GRANT AUTHENTICATE SERVER TO [DBMailLogin]

    GO

    -- Create a MSDB User for the Login

    USE [msdb]

    GO

    CREATE USER [DBMailLogin] FROM LOGIN [DBMailLogin]

    GO

    -- Add msdb login/user to the DatabaseMailUserRole

    EXEC msdb.dbo.sp_addrolemember @rolename = 'DatabaseMailUserRole', @membername = 'DBMailLogin';

    GO

    USE [TestDBMail]

    GO

    -- Sign the procedure with the certificate's private key

    ADD SIGNATURE TO OBJECT::[TestSendMail]

    BY CERTIFICATE [DBMailCertificate]

    WITH PASSWORD = '$tr0ngp@$$w0rd';

    GO

    -- This will succeed

    EXECUTE [dbo].[TestSendMail] 'someemail@domain.com', 'test', 'body'

    /*

    -- Cleanup

    USE [msdb]

    GO

    DROP USER [DBMailLogin]

    GO

    USE [master]

    GO

    DROP LOGIN [DBMailLogin]

    DROP CERTIFICATE [DBMailCertificate]

    DROP DATABASE [TestDBMail]

    -- Delete the certificate backup from disk

    */

    This will allow you to use permission chaining the database that the wrapper procedure exists in while enforcing best security practices in design.

    Jonathan Kehayias | Principal Consultant | MCM: SQL Server 2008
    My Blog | Twitter | MVP Profile
    Training | Consulting | Become a SQLskills Insider
    Troubleshooting SQL Server: A Guide for Accidental DBAs[/url]