locked
Is there a way to Get/Send email using exchange webservice without using autodiscover? RRS feed

  • Question

  • I have been trying to use the code in powershell below to test a send email using the webservice.

    As it appears according to this tool.

    https://testconnectivity.microsoft.com

    Autodiscover is not setup.. which I'm being told it is, but the tool tells me another story...

    Well, I would rather bypass the Autodiscovery item if at all possible...

    code sample:

    using System;
    using Microsoft.Exchange.WebServices.Data;

     


    namespace HelloWorld
    {
      class Program
      {
        static void Main(string[] args)
        {
          ExchangeService service = new ExchangeService(ExchangeVersion.Exchange<version and SP> );
          service.EnableScpLookup = false;
          service.Credentials = new WebCredentials("username", "pass", "domain");

         

          service.TraceEnabled = true;
          service.TraceFlags = TraceFlags.All;

    // # Commented out service.AutodiscoverUrl("Email account");


         service.Url = "https://<exchange url>/EWS/Exchange.asmx";

          EmailMessage email = new EmailMessage(service);

          email.ToRecipients.Add("<a href="mailto:emailaccount@.com">emailaccount@<email>.com");

          email.Subject = "HelloWorld";
          email.Body = new MessageBody("This is the first email I've sent by using the EWS Managed API");

          email.Send();
        }
      }
    }

    Please let me know if it is possible not to use autodiscovery .... and if there is a way to get this code to send email.. As I would later add a step to get the email downloaded to a sharepoint and or a file once I'm able to access the inbox.

    Wednesday, July 1, 2015 3:17 PM

All replies

  • Yes it is possible. You just have to set the service.Url property to a valid Exchange endpoint. You've got the line in there already:

    service.Url = "https://<exchange url>/EWS/Exchange.asmx";

    Just replace <exchange url> with the address of your CAS server.

    Wednesday, July 1, 2015 3:26 PM
  • Ok, I be a developer.. not an exchange person...

    what is the CAS server?

    when i use the code above it doesn't work, it still gives me the autodiscovery error message

    Wednesday, July 1, 2015 3:41 PM
  • CAS = Client Access Server

    You should be able to just use the URL you access the web interface (OWA) with. So if you can check email on that server with https://mydomain.com/owa/, you would just use https://mydomain.com/EWS/Exchange.asmx.

    If you're specifying the service URL, you should not be trying to make the Autodiscover call as it will continue to fail until Autodiscover is set up.
    Wednesday, July 1, 2015 4:05 PM
  • that exactly it:

    I don't want to use the autodiscovery in my code at all, I want to hit the Webservice straight on.

    I have tried the IPaddress of the server , the url of the owa.

    that how I have the current code:

    https://mydomain.com/EWS/Exchange.asmx.

    and I get the autodiscovery error message


    • Edited by SPSAdminTC Wednesday, July 1, 2015 4:24 PM
    Wednesday, July 1, 2015 4:13 PM
  • My mistake, I didn't notice you had that commented out in your example. Could you include the exact error message you're getting in your client code?

    Can you load the https://mydomain.com/EWS/Exchange.asmx page in your browser?

    In my experience, the Autodiscover call fails on the service.Autodiscover(...) call, but when the service URL is wrong, you won't get an error message until you actually try to do something (e.g. fetch email). It seems strange that you would get an Autodiscover error when your code isn't trying to make that call.
    Wednesday, July 1, 2015 4:42 PM
  • I'm able to hit the Service.wsdl

    the url gets changed when I try this in a browser

    https://mydomain.com or the IPaddress of exchange server /EWS/Exchange.asmx;

    to this:

    service.Url = "https://<IPAddress> or <domain> /ews/Services.wsdl"; (Error Message that Autodiscovery is not setup see below:

    I just noticed that the above code also throws this error
    Error    1    Cannot implicitly convert type 'string' to 'System.Uri'  

    I just really need to know how to get the code to STOP looking for the autodiscovery service

    Wednesday, July 1, 2015 5:18 PM
  • I've also noticed that the browser does the redirect, but the client code does seem to prefer the .asmx path.

    I forgot that the service.Url property expects a Uri type, not a string. I think you're actually executing old code when you didn't have the Autodiscover call commented out because of the compilation error.

    Try passing in the service.Url value as a Uri and see if that works.


    Wednesday, July 1, 2015 5:33 PM
  • I'm not sure i know what you mean by this ( C# newbie)

    "Try passing in the service.Url value as a Uri and see if that works."

    example please....


    I no longer even have that line in my code // # Commented out service.AutodiscoverUrl("Email account");  I removed it
    • Edited by SPSAdminTC Wednesday, July 1, 2015 5:36 PM
    Wednesday, July 1, 2015 5:35 PM
  • You're giving it a string, but it expects a Uri object, representing a Uniform Resource Identifier. Once you pass in a value of the appropriate type, you'll be able to compile.

    Do a search for "C# Uri" to find the appropriate constructor. You should be able to instantiate a new instance like you do in most other languages...

    Wednesday, July 1, 2015 5:42 PM
  • I no longer even have that line in my code // # Commented out service.AutodiscoverUrl("Email account");  I removed it
    Right, but your code won't compile until you've fixed the "Cannot implicitly convert type 'string' to 'System.Uri'" error. If you've gotten this far already, I'm confident you'll be able to sort out that error and get this working
    Wednesday, July 1, 2015 5:45 PM
  • Ok, this worked to get me past the autodiscovery error message

    new Uri ( );

    now I get an error on  email.Send();

    there seems to be an issue with the certificate, or something, is there a way to tell the code by pass the certificate error, as I can click thru the certificate error message and get the xml of the webservice.

    Wednesday, July 1, 2015 6:02 PM
  • You're almost there, you just need to use the Uri constructor that takes the URL string as a parameter. The service still needs to know about that .asmx page in order to connect. Check out the MSDN Uri page for more constructors.
    Wednesday, July 1, 2015 6:07 PM
  • I think I'm close if I can figure out how to use something like to to get me past the Certificate error message, as i can click past it and see the xml of the webservice

    I just do not understand where to put this in my code and if I can jsut cut and paste this code.. when i do it throws a ton of error messages

    Wednesday, July 1, 2015 6:44 PM
  • My understanding is that this is caused by self-signed certificates, though your situation may be different. If it is indeed the case, you might find this page useful:

    https://msdn.microsoft.com/en-us/library/office/jj900163%28v=exchg.150%29.aspx?f=255&MSPPError=-2147217396

    The first block of code on that page defines a function that takes in a certificate and validates it. The second code block enables it, and basically says "for my application, use this logic to validate certificates".

    The quick and dirty way to override this, which should absolutely not be used outside of a debugging/developing context, is by taking that piece of code and putting "return true;" inside the body. In that case you're no longer examining the certificate, but short-circuiting your application to accept all certificates, however shady.

    Either way, you should make that assignment to override the certificate validation callback before you try to connect.

    Wednesday, July 1, 2015 6:57 PM
  • I placed this code at the bottom of the code I have and I still get the SSL/TLS  Error

    private static bool CertificateValidationCallBack(
             object sender,
             System.Security.Cryptography.X509Certificates.X509Certificate certificate,
             System.Security.Cryptography.X509Certificates.X509Chain chain,
             System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
          // If the certificate is a valid, signed certificate, return true.
          if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
          {
            return true;
          }
    
          // If there are errors in the certificate chain, look at each error to determine the cause.
          if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
          {
            if (chain != null && chain.ChainStatus != null)
            {
              foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
              {
                if ((certificate.Subject == certificate.Issuer) &&
                   (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
                {
                  // Self-signed certificates with an untrusted root are valid. 
                  continue;
                }
                else
                {
                  if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
                  {
                    // If there are any other errors in the certificate chain, the certificate is invalid,
                 // so the method returns false.
                    return false;
                  }
                }
              }
            }
    
            // When processing reaches this line, the only errors in the certificate chain are 
        // untrusted root errors for self-signed certificates. These certificates are valid
        // for default Exchange server installations, so return true.
            return true;
          }
          else
          {
         // In all other cases, return false.
            return false; (changed this to "true" Same error message also)
          }
        }
    

    Wednesday, July 1, 2015 7:06 PM
  • Did you get the code from the second block?

    In your code you'll need to assign that function as your new certificate validation callback, so you'll need this line:

    ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
    Put this as the first part of your client app logic, before you instantiate the new ExchangeService instance. The value on the right of that expression is the function you created, so you just need to make sure that it's in scope when you put that line in your code.
    Wednesday, July 1, 2015 7:15 PM
  • this is throwing an error

    ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;

    says it doesn't exist in the curent context

    Wednesday, July 1, 2015 7:23 PM
  • this is throwing an error

    ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;

    says it doesn't exist in the curent context

    Well it's definitely a scope issue, but I can't be sure which side of the expression is responsible without seeing all of your code. Assuming you're using Visual Studio, it should underline the problematic part of the expression and give you something to go off of. If it's on the left side, it's probably a namespace issue, and if it's on the right then it's a question of visibility.

    I'm going to go out on a limb though and guess that you are not importing the System.Net namespace, which defines ServicePointManager. Try changing the left side of the expression to:

    System.Net.ServicePointManager.ServerCertificationCallback

    I can guarantee you'll run into these kinds issues as you progress, so I'd encourage you to explore more about how C# and .NET work. http://www.dotnetperls.com is a fantastic resource for learning more about this great language.


    • Edited by Tarnt Karntington Wednesday, July 1, 2015 7:40 PM don't understand how left and right work
    Wednesday, July 1, 2015 7:39 PM
  • Ok, I solved it, it actually sent me an email .. I was celebrating.... sorry for the long delay on status of code ..

    now, I get the fun of figuring out how to download emails with attachments...

    thanks for your help....

    Wednesday, July 1, 2015 7:45 PM
  • Awesome, glad you got it sorted out. Celebrate away.
    Wednesday, July 1, 2015 7:56 PM