I want to send email in RunBaseBatch, but I get error 0x80040211 (unknown).
I found in google that means:
The message could not be sent to the SMTP server.
The transport error code was %2. The server response was %1
public void SendReport(str email)
{
SysMailer sm = new SysMailer();
;
sm.quickSend("axmail#domain.eu", email, "Test", strfmt("body"));
}
This method is called in Run method. And if I copy this source code into job that works. Additionally in Run method I use,
permissionSet = new Set(Types::Class);
permissionSet.add(new InteropPermission(InteropKind::ClrInterop));
permissionSet.add(new InteropPermission(InteropKind::ComInterop));
permissionSet.add(new InteropPermission(InteropKind::DllInterop));
CodeAccessPermission::assertMultiple(permissionSet);
Because your email seems to work in a job (client side), your email settings in AX are not the issue.
This is most likely an authentication issue.
Take a look at this article, which describes what your are experiencing.
On the client side, your current windows user is used to authenticate with the SMTP server.
In batch, the emails are sent from the AOS. That means that the account used for authentication, is the account under which the AOS service runs.
Your mail server probably doesn't accept connections from everyone.
Take a look here on how this is achieved.
You'll have to allow the user that runs your AOS service, to authenticate to your mail server.
Related
I need to make calls to a rest API service via BizTalk Send adapter. The API simply uses a token in the header for authentication/authorization. I have tested this in a C# console app using httpclient and it works fine:
string apiUrl = "https://api.site.com/endpoint/<method>?";
string dateFormat = "dateFormat = 2017-05-01T00:00:00";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("token", "<token>");
client.DefaultRequestHeaders.Add("Accept", "application/json");
string finalurl = apiUrl + dateFormat;
HttpResponseMessage resp = await client.GetAsync(finalurl);
if (resp.IsSuccessStatusCode)
{
string result = await resp.Content.ReadAsStringAsync();
var rootresult = JsonConvert.DeserializeObject<jobList>(result);
return rootresult;
}
else
{
return null;
}
}
however I want to use BizTalk to make the call and handle the response.
I have tried using the wcf-http adapter, selecting 'Transport' for security (it is an https site so security is required(?)) with no credential type specified and placed the header with the token in the 'messages' tab of the adapter configuration. This fails though with the exception: System.IO.IOException: Authentication failed because the remote party has closed the transport stream.
I have tried googling for this specific scenario and cannot find a solution. I did find this article with suggestions for OAUth handling but I'm surprised that even with BizTalk 2016 I still have to create a custom assembly for something so simple.
Does anyone know how this might be done in the wcf-http send adapter?
Yes, you have to write a custom Endpoint Behaviour and add it to the send port. In fact with the WCF-WebHttp adapter even Basic Auth doesn't work so I'm currently writing an Endpoint Behaviour to address this.
One of the issues with OAuth, is that there isn't one standard that everyone follows, so far I've had to write 2 different OAuth behaviours as they have implemented things differently. One using a secret and time stamp hashed to has to get a token, and the other using Basic Auth to get a token. Also one of them you could get multiple tokens using the same creds, whereas the other would expire the old token straight away.
Another thing I've had to write a custom behaviour for is which version of TLS the end points expects as by default BizTalk 2013 R2 tries TLS 1.0, and then will fail if the web site does not allow it.
You can feedback to Microsoft that you wish to have this feature by voting on Add support for OAuth 2.0 / OpenID Connect authentication
Maybe someone will open source their solution. See Announcement: BizTalk Server embrace open source!
Figured it out. I should have used the 'Certificate' for client credential type.
I just had to:
Add token in the Outbound HTTP Headers box in the Messages tab and select 'Transport' security and 'Certificate' for Transport client credential type.
Downloaded the certificate from the API's website via the browser (manually) and installed it on the local servers certificate store.
I then selected that certificate and thumbprint in the corresponding fields in the adapter via the 'browse' buttons (had to scroll through the available certificates and select the API/website certificate I was trying to connect to).
I discovered this on accident when I had Fiddler running and set the adapter proxy setting to the local Fiddler address (http://localhost:8888). I realized that since Fiddler negotiates the TLS connection/certificate (I enabled tls1.2 in fiddler) to the remote server, messages were able to get through but not directly between the adapter and the remote API server (when Fiddler WASN'T running).
I've an application that connects to Reporting Services in SQL Server 2008 R2.
The error is the following:
System.Net.WebException: The request failed with HTTP status 401: Unauthorized.
at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse
(SoapClientMessage message, WebResponse response, Stream responseStream,
Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke
(String methodName, Object[] parameters)
at Microsoft.SqlServer.ReportingServices2005.Execution.ReportExecutionService.LoadReport
(String Report, String HistoryID)
The application is running in production fine in 2 different customers, so it's not a codeing issue.
I'm trying to install it now on a customer's server, which is using AD. The SQL Server and the IIS is all in the same machine though, so I don't really care about AD.
It runs if I run IE as Administrator, but it doesn't work with other users. The ASP.NET app is connecting to SSRS using a user created in the local machine (called ReportingServicesUser), member of the ReportingServicesUser group.
Things I've tried:
Adding ReportingServicesUser to the Site Settings in the RS website (did the same for Network Service, IUSR, the Authenticated Users group, Local Service, etc)
Adding ReportingServicesUser to the folder permissions in the RS website (did the same for Network Service, IUSR, the Authenticated Users group, Local Service, etc)
Added permissions for that users to the databases (app database and RS related dbs)
Added NTFS permissions to the RS folders (I will double check though).
Connecting to the RS using http://localhost, http://computername and http://domain.com
For reference, the code is this (simplified version):
var service = new ReportExecutionService();
service.Credentials = new NetworkCredential("ReportingServicesUser", "password");
service.Url = "http://computername:90/ReportServer/ReportExecution2005.asmx";
service.ExecutionHeaderValue = new ExecutionHeader();
var execInfo = new ExecutionInfo();
execInfo = service.LoadReport("path-to-the-report", null);
===> Here it throws the exception
I've read a lot of posts and pages about this but I cannot get an answer that works for me.
OK, I've finally had to change the code to:
rs.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
and it worked. Probably there's another solution but I couldn't find it out.
Are you sure you gave "ReportingServicesUser" browse permissions for the specific report in ssrs? The request never made it to the server it seems but I would check \Reporting Services\LogFiles just to be certain.
Also, Your "report user" user needs to be defined on the reporting server with the credentials you send.
Is there a way to check if SmtpClient successfully delivered an email? SmtpClient.Send() does not appear to return anything other than an exception. So if the method completes is it safe to assume the email will be successfully sent to the appropriate email box? My code is below:
MailMessage emailMessage = new MailMessage();
emailMessage.Subject = SubjectText;
emailMessage.IsBodyHtml = IsBodyHtml;
emailMessage.Body = BodyText;
emailMessage.From = new MailAddress(Settings.Default.FromEmail,Settings.Default.FromDisplayName);
//add recipients
foreach (string recipientAddress in RecipientAddresses.Split(new char[{','},StringSplitOptions.RemoveEmptyEntries))
emailMessage.To.Add(recipientAddress);
using (SmtpClient smtpClient = new SmtpClient())
{
smtpClient.Send(emailMessage);
}
No, there is no reliable way to find out if a message was indeed delivered.
Doing so will require access to the end SMTP server for every person you are emailing.
If you do not get an exception, you can assume that the SMTP server did its best to deliver the email.
There's no way to be 100% sure that a mail message has been received when sent via SmtpClient due to the way email works. The fact that SmtpClient doesn't throw an exception essentially means that you've done everything right, but a failure can happen further down the line, for example:
The receiving mail server could reject the mail
An intermediate mail server could reject the mail
The server that SmtpClient is transmitting mail through could decide to refuse to transmit the mail
One solution you could use is to create an httphandler for your website images. If you send an HTML message which includes at least 1 image, then you could embed querystring data to the end of that image. This could even be something like a 1x1 transparent image. When the user reads the email, this sends the request to the server to fetch the image data, and in turn, you could capture that request and denote that the message was read.
This is not bulletproof however, because most email clients block images by default unless the user specifies they would like to view images in the email.
If the recipient e-mail address is valid you don't get an immediate return value about the successful delivery of the message; see the signature:
public void Send(MailMessage message)
The SMTP server will notify the sender (or whoever you specify for the notification) almost immediately with an 'Undeliverable' notification whenever the recipient e-mail address is invalid/fake.
SMTP servers are required to periodically retry delivery. When the recipient e-mail address is a valid address but for some reason the SMTP server could not deliver the message, the SMTP server will return a failure message to the sender if it cannot deliver the message after a certain period of time.
RFC 2821 contains more details.
From section 2.1 Basic Structure
In other words, message transfer can occur in a single connection
between the original SMTP-sender and the final SMTP-recipient, or can
occur in a series of hops through intermediary systems. In either
case, a formal handoff of responsibility for the message occurs: the
protocol requires that a server accept responsibility for either
delivering a message or properly reporting the failure to do so.
See sections 4.5.4 and 4.5.5
From section 6.1 Reliable Delivery and Replies by Email
If there is a delivery failure after acceptance of a message, the
receiver-SMTP MUST formulate and mail a notification message. This
notification MUST be sent using a null ("<>") reverse path in the
envelope. The recipient of this notification MUST be the address from
the envelope return path (or the Return-Path: line).
I have an ASP NET web server application that calls another process running on the same box that creates a pdf file and returns it. The second process requires a secure connection via SSL.
The second process has issued my ASP NET application with a digital certificate but I still cannot authenticate, getting a 403 error.
The code is a little hard to show but here's a simplified method ...
X509Certificate cert = X509Certificate.CreateFromCertFile("path\to\cert.cer");
string URL = "https://urltoservice?params=value";
HttpWebRequest req = HttpWebRequest.Create(URL) as HttpWebRequest;
req.ClientCertificates.Add(cert);
req.Credentials = CredentialCache.DefaultCredentials;
req.PreAuthenticate = true;
/// error happens here
WebResponse resp = req.GetResponse();
Stream input = resp.GetResponseStream();
The error text is "The remote server returned an error: (403) Forbidden."
Any pointers are welcome.
Finally fixed (wasted 6 hours on this *&%$##&)
I needed to grant access to the private keys on the digi cert to the account that the calling ASP.NET application runs under. This account is NETWORK SERVICE by default although you may want to run under a more restricted account.
Access is granted with the winhttpcertcfg tool, here's what got it working for me:
winhttpcertcfg -g -s "cert name" -c "LOCAL_MACHINE\MY" -a "NETWORK SERVICE"
where "cert name" is the CN of the digi cert.
More info at http://support.microsoft.com/kb/901183
Thanks to all who helped out with pointers on how to get this working :)
A 403 sounds like an authorization problem, not an authentication problem. It might be caused by the NTFS security settings on the files and folders accessed by your PDF service. Maybe it doesn't have permission to create the PDF file in the output folder?
Can you install the client certificate into your browser, and then access your PDF service through the browser? When you do that, do you still get a 403 or does it work?
Can you temporarily configure the PDF service to allow unencrypted HTTP connections? Does that make the problem go away?
From Windows Explorer, can you grant the "Network Service" account full control over the physical folder corresponding to the root of the PDF service site? Also grant it full control over any other directories it accesses. You should lock things down later after you've figured things out.
Or you can change the application pool to run under a different account - e.g. your own account.
Finally: if you're running IIS 7, you can turn on failed request tracing, which should give you a lot more info about why it failed.
Has anyone suddenly encountered login errors from their users trying to connect to salesforce.com from a Flex app using as3salesforce.swc?
I get the following error... password removed to protect the innocent...
App Domain = null
Api Server name = na3.salesforce.com
_internalServerUrl = https://na3.salesforce.com/services/Soap/u/14.0
loading the policy file: https://na3.salesforce.com/services/Soap/cross-domain.xml
Your application must be running on a https server in order to use https to communicate with salesforce.com!
login with creds
loading the policy file: https://na3.salesforce.com/services/crossdomain.xml
Your application must be running on a https server in order to use https to communicate with salesforce.com!
invoke login
intServerUrl is null
intServerUrl = https://na3.salesforce.com/services/Soap/u/14.0
_invoke login
'5A5D3012-7717-E3C2-9B39-FFBBFF1F1B47' producer set destination to 'DefaultHTTPS'.
Method name is: login
'direct_http_channel' channel endpoint set to http://localhost/pm_server/pm/
'5A5D3012-7717-E3C2-9B39-FFBBFF1F1B47' producer sending message 'E32C7199-72C1-B258-B483-FFBC1641173D'
'direct_http_channel' channel sending message:
(mx.messaging.messages::HTTPRequestMessage)#0
body = "<se:Envelope xmlns:se="http://schemas.xmlsoap.org/soap/envelope/"><se:Header xmlns:sfns="urn:partner.soap.sforce.com"/><se:Body><login xmlns="urn:partner.soap.sforce.com" xmlns:ns1="sobject.partner.soap.sforce.com"><username>simon.palmer#dialectyx.com</username><password>******</password></login></se:Body></se:Envelope>"
clientId = (null)
contentType = "text/xml; charset=UTF-8"
destination = "DefaultHTTPS"
headers = (Object)#1
httpHeaders = (Object)#2
Accept = "text/xml"
SOAPAction = """"
X-Salesforce-No-500-SC = "true"
messageId = "E32C7199-72C1-B258-B483-FFBC1641173D"
method = "POST"
recordHeaders = false
timestamp = 0
timeToLive = 0
url = "https://na3.salesforce.com/services/Soap/u/14.0"
'5A5D3012-7717-E3C2-9B39-FFBBFF1F1B47' producer connected.
Method name is: login
Error: Ignoring policy file at https://na3.salesforce.com/crossdomain.xml due to meta-policy 'by-content-type'.
'5A5D3012-7717-E3C2-9B39-FFBBFF1F1B47' producer acknowledge of 'E32C7199-72C1-B258-B483-FFBC1641173D'.
responseType: Fault
Saleforce Soap Fault: sf:INVALID_LOGIN
INVALID_LOGIN: Invalid username, password, security token; or user locked out.
Comunication Error : sf:INVALID_LOGIN : INVALID_LOGIN: Invalid username, password, security token; or user locked out. : [object Object]
Obviously nobody else out there is building Flex apps on top of salesforce.com..
yippee, I'm first.
Anyhow, I just found out that this is a bug at salesforce.com as at 6th December 2008. The issue is that the scripts which handle login do not cope adequately with the redirect necessary because of load balancing on the salesforce.com servers.
It should be possible to go through the www front door of salesforce.com's api with a URL such as...
"https://www.salesforce.com/services/Soap/u/13.0";
where the 13 represents the version of their API you are targetting. However, all users are actually assigned to a specific server, so the front door should redirect the login request to the approriate place, and it doesn't if you are coming from Flex.
A workround is to specify your server in the URL, such as...
"https://na5.salesforce.com/services/Soap/u/13.0";
...which is what I was doing. That's fine if you are a single user accessing the same resources continually and your account remains attached to that server. However if...
You are distributing your app so anyone who has a salesforce.com enterprise account can log in OR
Your account gets moved because of some internal load balancing (which is what happened to me)
then the approach of providing a fixed server won't work.
The bug (as far as I understand it) is that the www route doesn't adequately redirect to your host server. Last intelligence was that it will be fixed "soon".
I wish I could mark this as the answer...