You are running into the dreaded 'sandboxed' mode of the EXECUTE AS
context, as described in Extending Database Impersonation by Using EXECUTE AS. In short code running under EXECUTE AS USER ...
is trusted only inside the database context, not at the instance context.
There are three ways out:
- the easy way: mark the current database as TRUSTWORTHY
ALTER DATABASE [...] SET TRUSTWORTHY ON;
- the correct way out: use code signing
- the cheat: use
EXECUTE AS LOGIN
If in your environment the dbo
of the current database is trusted then you can go with TRUSTWORTHY. It will work, but if this property is set then any db_owner
in the current DB can elevate himself to server admin.
If you want a 'correct' solution then:
- move this code in an stored proc
- sign the stored proc with a certificate
- drop the private key (so that it can never be used again to sign anything)
- export the public key, import it in
[msdb]
- create user in
[msdb]
derived from this certificate - grant necessary permissions (AUTHENTICATE, EXECUTE on sp_send_mail) to the certificate derived user
Trivial, heh? See Call a procedure in another database from an activated procedure for an example.
I totally don't recommend using EXECUTE AS LOGIN
instead.