You are running into the dreaded 'sandboxed' mode of the `EXECUTE AS` context, as described in [Extending Database Impersonation by Using EXECUTE AS](http://msdn.microsoft.com/en-us/library/ms188304.aspx). 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][1] `ALTER DATABASE [...] SET TRUSTWORTHY ON;`
 - the correct way out: use [code signing][2]
 - 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:

 1. move this code in an stored proc
 2. sign the stored proc with a certificate
 3. drop the private key (so that it can never be used again to sign anything)
 4. export the public key, import it in `[msdb]`
 5. create user in `[msdb]` derived from this certificate
 6. grant necessary permissions (AUTHENTICATE, EXECUTE on sp_send_mail) to the certificate derived user 

Trivial, heh? BTW, every time you modify the signed stored proc the signature is lost and the procedure has to be repeated. See [Call a procedure in another database from an activated procedure](http://rusanu.com/2006/03/07/call-a-procedure-in-another-database-from-an-activated-procedure/) for an example.

I totally don't recommend using `EXECUTE AS LOGIN` instead.

  [1]: http://technet.microsoft.com/en-us/library/ms187861.aspx
  [2]: http://msdn.microsoft.com/en-us/library/ms345102.aspx