locked
An unexpected error occurred - when sending mail RRS feed

  • Question

  •  

    Having issues sending mail when the application is released into a production enviroment. 
    It works in develoment and test, but fails miserablly in production.

    It is pretty straight forward.  The application saves and email, then saves the attacment, and
    finally tells CRM that it can be emailed.

     

    CODE:

     

    private bool SendEmail(Guid email_identity) 
    {
    this._CrmContext = this.CrmServiceConnection();

    SendEmailRequest ser = new SendEmailRequest();
    ser.EmailId = email_identity;
    ser.TrackingToken = string.Empty;
    ser.IssueSend = true;
    	SendEmailResponse res = (SendEmailResponse)this._CrmContext.Execute(ser); 
    this._CrmContext.Dispose();
    	return res.Subject.Equals(""); 
    }

    ERROR MESSAGE:

    An unexpected error occurred.

    Server stack trace: at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc) at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at Microsoft.Xrm.Sdk.IOrganizationService.Execute(OrganizationRequest request) at Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy.ExecuteCore(OrganizationRequest request) at Microsoft.Xrm.Client.Services.OrganizationService.InnerOrganizationService.UsingService[TResult](Func`2 action) at Microsoft.Xrm.Client.Services.CachedOrganizationService.InnerExecute(OrganizationRequest request) at Microsoft.Xrm.Client.Services.OrganizationServiceCache.InnerExecute[TRequest,TResponse,TResult](TRequest request, Func`2 execute, Func`2 selector, String selectorCacheKey) at Microsoft.Xrm.Client.Services.CachedOrganizationService.Execute[T](OrganizationRequest request, Func`2 selector, String selectorCacheKey) at Microsoft.Xrm.Client.Services.CachedOrganizationService.Execute[T](OrganizationRequest request) at Microsoft.Xrm.Sdk.Client.OrganizationServiceContext.Execute(OrganizationRequest request) at Hanlon.Data.CRM.Advisor.SendEmail(Guid email_identity) in h:\visual studio 2010\Projects\HypotheticalReportSolution\CrmAccess\Advisor.cs:line 188 at Hanlon.Data.CRM.Advisor.AdvisorSendEmail(String subject, String body, String hypoReportPath, Guid crmSystemUserIdentity) in h:\visual studio 2010\Projects\HypotheticalReportSolution\CrmAccess\Advisor.cs:line 114 at HypotheticalReportCrmSite.HypotheticalReport.AcceptanceWorkFlow() in h:\visual studio 2010\Projects\HypotheticalReportSolution\HypotheticalReportCrmSite\HypotheticalReport.aspx.cs:line 207


    Paul Baratelli .NET Developer

     

     


    Monday, August 15, 2011 8:30 PM

Answers

  • Hi,
    If you have enabled CRM EMail Tracking Token on the production server then you must have to pass the Tracking Token value into the email, try the following code below:
     
    private bool SendEmail(Guid email_identity) {  
    
     this._CrmContext = this.CrmServiceConnection();
     SendEmailRequest ser = new SendEmailRequest();
      ser.EmailId = email_identity;  

     // Add Tracking Token to SendEmail Request
     GetTrackingTokenEmailRequest jj_GetTrackingTokenEmailRequest = new GetTrackingTokenEmailRequest();
     GetTrackingTokenEmailResponse jj_GetTrackingTokenEmailResponse = null;
     jj_GetTrackingTokenEmailResponse = (GetTrackingTokenEmailResponse)this._CrmContext.Execute(jj_GetTrackingTokenEmailRequest);
     ser.TrackingToken = jj_GetTrackingTokenEmailResponse.TrackingToken;
     
     ser.IssueSend = true;   
     SendEmailResponse res = (SendEmailResponse)this._CrmContext.Execute(ser);  
     this._CrmContext.Dispose();    
     return res.Subject.Equals("");
    }

    Jehanzeb Javeed

    http://worldofdynamics.blogspot.com
    Linked-In Profile |CodePlex Profile

    If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".

    • Marked as answer by Paul Baratelli Wednesday, August 17, 2011 4:01 PM
    Tuesday, August 16, 2011 4:05 PM
  • You can either:

    1. Run your application under an identity with the applicable CRM privileges
    2. Explicitly set your credentials via the connection to the CRM - this will required either hard-coding (bad) or configuration of some kind - exactly how you do this will depend on the architecture of your application and how you are instantiating the connection to the CRM
    3. Specify the CallerId on your OrganizationServiceProxy - this allows you to impersonate the user specified by the CallerId GUID.  For this to succeed the user identity specified in the CRM connection must possess the prvActOnBehalfOfAnotherUser privilege

    See the SDK for more details of CallerId impersonation:

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

    Sample:

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


    --pogo (pat) @ pogo69.wordpress.com
    • Marked as answer by Paul Baratelli Wednesday, August 17, 2011 4:00 PM
    Tuesday, August 16, 2011 9:39 PM

All replies

  • Hi,

    Try put your code into the following try{} catch(..) expection to get the exact error details:

    try
    {
    //Your code
    }
    catch(SoapException e)
    {
    throw new Exception(e.Detail.InnerText);
    }


    Jehanzeb Javeed

    http://worldofdynamics.blogspot.com
    Linked-In Profile |CodePlex Profile

    If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    Monday, August 15, 2011 11:08 PM
  •  

    Jehanzeb,

    Ran the code.  The inner exception throws a "not an instance of an object error".

     

    Paul


    Paul Baratelli .NET Developer
    Tuesday, August 16, 2011 3:56 PM
  • Hi,
    If you have enabled CRM EMail Tracking Token on the production server then you must have to pass the Tracking Token value into the email, try the following code below:
     
    private bool SendEmail(Guid email_identity) {  
    
     this._CrmContext = this.CrmServiceConnection();
     SendEmailRequest ser = new SendEmailRequest();
      ser.EmailId = email_identity;  

     // Add Tracking Token to SendEmail Request
     GetTrackingTokenEmailRequest jj_GetTrackingTokenEmailRequest = new GetTrackingTokenEmailRequest();
     GetTrackingTokenEmailResponse jj_GetTrackingTokenEmailResponse = null;
     jj_GetTrackingTokenEmailResponse = (GetTrackingTokenEmailResponse)this._CrmContext.Execute(jj_GetTrackingTokenEmailRequest);
     ser.TrackingToken = jj_GetTrackingTokenEmailResponse.TrackingToken;
     
     ser.IssueSend = true;   
     SendEmailResponse res = (SendEmailResponse)this._CrmContext.Execute(ser);  
     this._CrmContext.Dispose();    
     return res.Subject.Equals("");
    }

    Jehanzeb Javeed

    http://worldofdynamics.blogspot.com
    Linked-In Profile |CodePlex Profile

    If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".

    • Marked as answer by Paul Baratelli Wednesday, August 17, 2011 4:01 PM
    Tuesday, August 16, 2011 4:05 PM
  • Jehanzeb,

    Added the code, but the same error is still popping (though the code will help as token tracking is turned on).

    Did alot of research into the messages.

    The messages that are sent are sent by ME and Createby me when I am in my development enviroment and logged in.

    When I move the application to production, the messages are sent by me BUT are CreatedBy System.  System does not
    permissions to send email and is Disabled in the systemuser view. 

    Is there anyway to change the CreatedBy through the SDK? Currently this feature is blocked by the crmsvrutil.exe file.

    I suspect that this is the issue that I need to code around.

     

    Paul Baratelli

     


    Paul Baratelli .NET Developer
    Tuesday, August 16, 2011 8:28 PM
  • Hi,

    Can you paste the code for function CrmServiceConnection(), i believe you can imporsonate as different CRM user while getting the service object. Are you running your code from external applicaiton?


    Jehanzeb Javeed

    http://worldofdynamics.blogspot.com
    Linked-In Profile |CodePlex Profile

    If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".
    Tuesday, August 16, 2011 8:50 PM
  • If you have enabled CRM EMail Tracking Token on the production server then you must have to pass the Tracking Token value into the email

    As a clarification; this is not accurate.  If you leave the Tracking Token blank, set to null, or do not set it at all, a tracking token will be generated automatically.  From the SDK (and verified from working code):

    The tracking token is used to correlate an e-mail with a context. You can generate a tracking token with the GetTrackingTokenEmailRequest message. If this property is unspecified it defaults to null. In this case, the SendEmailRequest message generates a tracking token automatically.


    --pogo (pat) @ pogo69.wordpress.com
    Tuesday, August 16, 2011 9:29 PM
  • You can either:

    1. Run your application under an identity with the applicable CRM privileges
    2. Explicitly set your credentials via the connection to the CRM - this will required either hard-coding (bad) or configuration of some kind - exactly how you do this will depend on the architecture of your application and how you are instantiating the connection to the CRM
    3. Specify the CallerId on your OrganizationServiceProxy - this allows you to impersonate the user specified by the CallerId GUID.  For this to succeed the user identity specified in the CRM connection must possess the prvActOnBehalfOfAnotherUser privilege

    See the SDK for more details of CallerId impersonation:

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

    Sample:

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


    --pogo (pat) @ pogo69.wordpress.com
    • Marked as answer by Paul Baratelli Wednesday, August 17, 2011 4:00 PM
    Tuesday, August 16, 2011 9:39 PM
  • Here is the connection code:

        public static CrmOrganizationServiceContext CrmServiceConnection(string CrmConnectionString)
        {
          CrmConnection conn = CrmConnection.Parse(CrmConnectionString);
          Uri organizationUri = conn.ServiceUri;
          Uri homeRealmUri = null; // conn.HomeRealmUri;
    
          ClientCredentials client = new ClientCredentials();
          // client.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
    
          client.Windows.ClientCredential.Domain = "[Domain]";
    
          client.Windows.ClientCredential.UserName = "[UserName]";
          client.Windows.ClientCredential.Password = "[Password]";
    
          OrganizationServiceProxy orgProxy = new OrganizationServiceProxy(organizationUri, homeRealmUri, client, null);
          orgProxy.EnableProxyTypes();
          IOrganizationService service = (IOrganizationService)orgProxy;
    
          // Create Service to pass to below code
          CrmOrganizationServiceContext cosc = new CrmOrganizationServiceContext(service);
    
          return cosc;
        }
    


    The user's credentials do not seem to be passed using System.Net....DefaultNetworkCredentials.  I added my own credentials and the process worked.  In the current enviroment, it seems the users are vetted through the active directory and if they are listed in the CRM application they are allowed in and their network credientials persist through the CRM application.

    When going thru the web application, it uses the System account (which on our system does not allow emailing or anything else).

    MRCRM

    The Tracking Token is working with Jehanzeb's code consistently where previously it seemed sporatic, though I had the token set to Empty.String before and not null.   I am going to review the CallerId information.  It sounds feasible to me in my application and I would prefer cleaner more effective code.

    Paul Baratelli


    Paul Baratelli .NET Developer
    Wednesday, August 17, 2011 12:29 PM
  • Things worked out great using the CallerID. The CRM Email function is now working
    perfectly!

    Here is the updated (Hopefully production level) code for the static function allowing the transactions executed 
    through the connection to act on behalf of a CRM user (The user needs permissions to Act on Behalf of other users).

    References:
     
    using System;
    using System.ServiceModel.Description;
    
    using Microsoft.Xrm.Sdk.Client;
    using Microsoft.Xrm.Client;
    using Microsoft.Xrm.Sdk;
    
    using Microsoft.Crm.Sdk;
    using Microsoft.Crm.SdkTypeProxy;

    CODE:
        /// <summary>
        /// Static function: Sets up a connection string and a CRM user GUID for creation of a CrmOrganizationServiceContext
        /// Object. The caller_id allows the connection to act on behalf of other CRM user as long as the user
        /// is set to Act on Behalf of other users.
        /// </summary>
        /// <param name="CrmConnectionString">String used to connect to instance of CRM. 
        ///                  i.e. http://<server>/<organization>/XRMServices/2011/Organization.svc
        /// </param>
        /// <param name="caller_id">A SystemUser Entity GUID related to the CRM account that will act on 
        ///             behalf of other CRM user transactions executed through the connection</param>
        /// <returns>CrmOrganizationServiceContext</returns>
        public static CrmOrganizationServiceContext CrmServiceConnectionWithImpersonation(string crmConnectionString, Guid caller_id)
        {
          // Parse the connection string into a CrmConnection Object. 
          CrmConnection conn = CrmConnection.Parse(crmConnectionString);
    
          // Create Uri objects from the CrmConnection Object
          Uri organizationUri = conn.ServiceUri;
          Uri homeRealmUri = null;
    
          // Get Default Client Credentials. In CRM, this will default to using the CRM System account
          // when project is released onto a production server
          ClientCredentials client = new ClientCredentials();
          client.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
    
          // Create our Proxy! <== notice excitement
          OrganizationServiceProxy orgProxy = new OrganizationServiceProxy(organizationUri, homeRealmUri, client, null);
    
          // Enable Proxy Types to allow Early-Binding to data ojects
          // (Note: To create Early-Binding, use crmsvrutil.exe in SDK to 
          //    create a class file containing ORM information of current
          //    CRM entities)
          orgProxy.EnableProxyTypes();
    
          // Set the CallerId to the person who is connecting on behalf 
          // of Another CRM User (This can be on behalf of the user himself! 
          // i.e. Bob Springfield connecting on behalf of Bob Springfield
          orgProxy.CallerId = caller_id;
    
          // Create our Service!!!! <== notice the extreme excitement
          IOrganizationService service = (IOrganizationService)orgProxy;
    
          // Send a new CrmOrganizationServiceContext Object back to the caller
          return new CrmOrganizationServiceContext(service);
        }

     
     
    Thanks guys! 

    Paul Baratelli


    Paul Baratelli .NET Developer


    • Edited by Paul Baratelli Wednesday, August 17, 2011 4:16 PM Forgot to add referenced libraries
    Wednesday, August 17, 2011 3:59 PM