A mail server returns this error when I send mail with several recipients :
Remote Server returned 'mx.spamexperts.com #5.0.0 smtp; 550 Messages should have one or no To headers, not 5.'
It happens when I use addRecipient method of JavaMail multiple times. If I use setRecipient instead with an array of email address, it works.
This is the consequence of the addHeader method in javax.mail.internet.InternetHeaders class. Here is the piece of code which is the cause of this issue :
for (int i = headers.size() - 1; i >= 0; i--) {
InternetHeader h = (InternetHeader)headers.get(i);
if (name.equalsIgnoreCase(h.getName())) {
if (addReverse) {
pos = i;
} else {
headers.add(i + 1, new InternetHeader(name, value));
return;
}
}
// marker for default place to add new headers
if (h.getName().equals(":"))
pos = i;
}
What do you think about that ? Why JavaMail adds new To header each time we use addRecipient if some mail server does not accept it ?
You must be using a very old version of JavaMail. This was fixed in JavaMail 1.4.4, over 5 years ago. The current version is 1.5.5.
Related
I have a code that fetches conversations and the messages inside them (a specific number of pages). It works most of the time, but for certain conversations it throws an exception, such as:
Exception in thread "main" com.restfb.exception.FacebookOAuthException: Received Facebook error response of type OAuthException: Unknown path components: /[id of the message]/messages (code 2500, subcode null)
at com.restfb.DefaultFacebookClient$DefaultGraphFacebookExceptionMapper.exceptionForTypeAndMessage(DefaultFacebookClient.java:1192)
at com.restfb.DefaultFacebookClient.throwFacebookResponseStatusExceptionIfNecessary(DefaultFacebookClient.java:1118)
at com.restfb.DefaultFacebookClient.makeRequestAndProcessResponse(DefaultFacebookClient.java:1059)
at com.restfb.DefaultFacebookClient.makeRequest(DefaultFacebookClient.java:970)
at com.restfb.DefaultFacebookClient.makeRequest(DefaultFacebookClient.java:932)
at com.restfb.DefaultFacebookClient.fetchConnection(DefaultFacebookClient.java:356)
at test.Test.main(Test.java:40)
After debugging I found the ID that doesn't work and tried to access it from graph-api, which results in an "unknown path components" error. I also attempted to manually find the conversation in me/conversations and click the next page link in the graph api explorer which also lead to the same error.
Is there a different way to retrieve a conversation than by ID? And if not, could someone show me an example to verify first if the conversation ID is valid, so if there are conversations I can't retrieve I could skip them instead of getting an error. Here's my current code:
Connection<Conversation> fetchedConversations = fbClient.fetchConnection("me/Conversations", Conversation.class);
int pageCnt = 2;
for (List<Conversation> conversationPage : fetchedConversations) {
for (Conversation aConversation : conversationPage) {
String id = aConversation.getId();
//The line of code which causes the exception
Connection<Message> messages = fbClient.fetchConnection(id + "/messages", Message.class, Parameter.with("fields", "message,created_time,from,id"));
int tempCnt = 0;
for (List<Message> messagePage : messages) {
for (Message msg : messagePage) {
System.out.println(msg.getFrom().getName());
System.out.println(msg.getMessage());
}
if (tempCnt == pageCnt) {
break;
}
tempCnt++;
}
}
}
Thanks in advance!
Update: Surrounded the problematic part with a try catch as a temporary solution, also counted the number of occurrences and it only effects 3 out of 53 conversations. I also printed all the IDs, and it seems that these 3 IDs are the only ones that contain a "/" symbol, I'm guessing it has something to do with the exception.
The IDs that work look something like this: t_[text] (sometimes a "." or a ":" symbol) and the ones that cause an exception are always t_[text]/[text]
conv_id/messages is not a valid graph api call.
messages is a field of conversation.
Here is what you do (single call to api):
Connection<Conversation> conversations = facebookClient.fetchConnection("me/conversations", Conversation.class);
for (Conversation conv : conversations.getData()) {
// To get list of messages for given conversation
LinkedList<Message> allConvMessagesStorage = new LinkedList<Message>();
Connection<Message> messages25 = facebookClient.fetchConnection(conv.getId()+"/messages", Message.class);
//Add messages returned
allConvMessagesStorage.addAll(messages25.getData());
//Check if there is next page to fetch
boolean progress = messages25.hasNext();
while(progress){
messages25 = facebookClient.fetchConnectionPage(messages25.getNextPageUrl(), Message.class);
//Append next page of messages
allConvMessagesStorage.addAll(messages25.getData());
progress = messages25.hasNext();
}
}
I am attempting to create new Interactions programmatically on Genesys Platform SDK 8.5 for Java.
I use the example on the API reference
public void createInteraction(String ixnType, String ixnSubtype, String queue) throws Exception
{
RequestSubmit req = RequestSubmit.create();
req.setInteractionType(ixnType);
req.setInteractionSubtype(ixnSubtype);
req.setQueue(queue);
req.setMediaType("email");
Message response = mPMService.getProtocol("IxnSrv").request(req);
if(response == null || response.messageId() != EventAck.ID) {
// For this sample, no error handling is implemented
return;
}
EventAck event = (EventAck)response;
mInteractionId = event.getExtension().getString("InteractionId");
}
However, this gives me an Unsupported protocol element error.
'EventError' (126) attributes:
attr_error_desc [str] = "Unsupported protocol element"
attr_ref_id [int] = 2
attr_error_code [int] = 4
How do I create a new Interaction programmatically?
Interaction server should be connected with ClientType as either MediaServer or AgentApplication for this request(RequestSubmit).
First of all, you must open your protocol as Media Server. After that you must submit your interaction to interaction server.
Firstly your protocol config must be like this;
interactionServerConfiguration.ClientName = "TestClient";
interactionServerConfiguration.ClientType = InteractionClient.MediaServer;
// Register this connection configuration with Protocol Manager
protocolManagementService.Register(interactionServerConfiguration);
Note : You must have MediaServer type application definition on your Configuration Env., you must see it in CME.
After open you connection to ixn server. You can submit your interaction what you like. Even you can create new type interaction just like i do. I did for our coopate sms system. Its name is not important. We defined it on our bussiness attribute, so our agent can send coopate 3rd party sms system from their agent desktop. Without new extension or new license :) Just tricked it system. Also genesys allows it. i know it because we are genesys official support team in our country :) (But agent seat license may be required depends on agent head count).
RequestSubmit request = RequestSubmit.Create();
request.TenantId = 1;
request.MediaType = "email";
request.Queue = c_inboundQueue;
request.InteractionType = "Inbound";
request.InteractionSubtype = "InboundNew";
// Prepare the message to send. It is inserted in the request as UserData
KeyValueCollection userData =
new KeyValueCollection();
// Prepare the message to send
userData.Add("Subject", "subject goes here");
request.UserData = userData; protocolManagementService[c_interactionServerConfigurationIdentifier].Send(request);
Turns out I needed to set ClientType to InteractionClient.ReportingEngine.
In Spring I set some cookies I need for my websocket:
Cookie ck = new Cookie("session", request.getSession().getId());
ck.setDomain(".mydomain.com");
ck.setPath("/");
ck.setVersion(1);
Cookie secretCookie = new Cookie("scrt", secret);
secretCookie.setDomain(".mydomain.com");
secretCookie.setPath("/");
secretCookie.setVersion(1);
response.addCookie(secretCookie);
response.addCookie(ck);
But when I read the header of the websocket handshake, the value of the cookie field only consists of a string which looks like this:
session=foobar; scrt=foomart
When you try to parse this value by HttpCookie.parse(); the HTTPCookie will try to identify the version of the cookie.
private static int guessCookieVersion(String header) {
int version = 0;
header = header.toLowerCase();
if (header.indexOf("expires=") != -1) {
// only netscape cookie using 'expires'
version = 0;
} else if (header.indexOf("version=") != -1) {
// version is mandatory for rfc 2965/2109 cookie
version = 1;
} else if (header.indexOf("max-age") != -1) {
// rfc 2965/2109 use 'max-age'
version = 1;
} else if (startsWithIgnoreCase(header, SET_COOKIE2)) {
// only rfc 2965 cookie starts with 'set-cookie2'
version = 1;
}
return version;
}
If the Value is 0, which is wrong but the case here, the HttpCookie will only parse the first entry.
If you force version to be 1, this won't work either, since HttpCookie is expecting comma seperated values. splitMultiCookies(String header)
Is there any way to fix this but writing my own parser?
It is funny because a cookie has no field "version" anymore. I can find a reference to it in the RFC2109 (1997), but it is not there anymore in RFC6265 (2011). Actually, the cookie API in .NET does not provide a built-in method to set such property (that is the reason this caught my attention). Check that the browser is actually sending that data as part of the handshake, maybe the browser is ignoring it.
when i try to setExpressCheckout, i get ack = success but not token return.
the version of paypal api is 87.0
Here the wsdl link : https://www.sandbox.paypal.com/wsdl/PayPalSvc.wsdl
here to command i use in axis2-1.6.1 to generate java code
-uri https://www.sandbox.paypal.com/wsdl/PayPalSvc.wsd -p com.paypal.soap
here the link to the java code that generated using axis2 https://docs.google.com/open?id=0B97cB4uxjmztbGgxRER6VjBWcWc
here the code for SetExpressCheckout
PaymentDetailsType paymentDetails = new PaymentDetailsType();
BasicAmountType orderTotal = new BasicAmountType();
orderTotal.setCurrencyID(CurrencyCodeType.USD);
orderTotal.setString("10.00");
paymentDetails.setOrderTotal(orderTotal);
paymentDetails.setPaymentAction(PaymentActionCodeType.Sale);
SetExpressCheckoutRequestDetailsType requestDetailsType = new SetExpressCheckoutRequestDetailsType();
requestDetailsType.setCancelURL(buyer.getCancelUrl());
requestDetailsType.setReturnURL(buyer.getReturnUrl());
requestDetailsType.setPaymentDetails(new PaymentDetailsType[]{paymentDetails});
SetExpressCheckoutRequestType requestType = new SetExpressCheckoutRequestType();
requestType.setVersion("87.0");
requestType.setSetExpressCheckoutRequestDetails(requestDetailsType);
SetExpressCheckoutReq req = new SetExpressCheckoutReq();
req.setSetExpressCheckoutRequest(requestType);
RequesterCredentials requesterCredentials = new RequesterCredentials();
CustomSecurityHeaderType customSecurityHeaderType = new CustomSecurityHeaderType();
UserIdPasswordType userIdPasswordType = new UserIdPasswordType();
userIdPasswordType.setUsername("<username>");
userIdPasswordType.setPassword("<pass>");
userIdPasswordType.setSignature("<signature>");
customSecurityHeaderType.setCredentials(userIdPasswordType);
requesterCredentials.setRequesterCredentials(customSecurityHeaderType);
String endPoint = null;
endPoint = "https://api-3t.sandbox.paypal.com/2.0/"; //sandbox API Signature
PayPalAPIInterfaceServiceStub stub = new PayPalAPIInterfaceServiceStub(endPoint);
stub._getServiceClient().getOptions().setProperty(HTTPConstants.CHUNKED, false);
SetExpressCheckoutResponse setExpressCheckout = stub.setExpressCheckout(req, requesterCredentials);
SetExpressCheckoutResponseType checkoutResponse = setExpressCheckout.getSetExpressCheckoutResponse();
Calendar timestamp = checkoutResponse.getTimestamp();
String strdate = null;
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
if (timestamp != null) {
strdate = sdf.format(timestamp.getTime());
}
System.out.println("Date:" + strdate);
System.out.println("CorrelationID:" + checkoutResponse.getCorrelationID());
System.out.println("ack :" + checkoutResponse.getAck());
if (checkoutResponse.getErrors() != null && checkoutResponse.getErrors().length > 0) {
PayPalAPIInterfaceServiceStub.ErrorType[] errors = checkoutResponse.getErrors();
for (int i = 0; i < errors.length; i++) {
System.out.println(errors[i].getErrorCode());
System.out.println(errors[i].getLongMessage());
}
}
System.out.println("token:" + checkoutResponse.getToken());
here the result that i get
Date:17/04/2012 12:33:38
CorrelationID:a7c9fe7283bd
ack :Success
token:null
how i get ack success but token is null?
the contact person for paypal said that there is an EC token already be generated for CorrelationID:a7c9fe7283bd .
thanks in advance.
i have to use setExpressCheckoutResponse.getExtraElement().getText() to get the token. why setExpressCheckoutResponse.getToken() return null?
If you look into mentioned wsdl file, at the beginning you'll notice the following:
<wsdl:definitions
ns:version="89.0"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.xmlsoap.org/wsdl/"
... >
Meaning that the version of API which should be used is 89.0 - don't remember where it's specified in PayPal API documentation, but this was mentioned there for sure.
Let me know if you still encounter this issue, since I've managed to set up PayPal Express Checkout using SOAP in Java recently and can help with that.
I just came across this issue and found the answer (this is for C#, I am not sure if it applies to Java):
https://www.x.com/developers/paypal/forums/soap/paypal-api-aa-and-net-wcf-undeserialized-fields
Look in the generated code for the web service (Reference.cs) and find the AbstractResponseType. The last property is Any(). Change the attribute to match this (to ignore the property):
[System.Xml.Serialization.XmlIgnoreAttribute()]
public System.Xml.XmlElement Any {
get {
return this.anyField;
}
set {
this.anyField = value;
}
}
Following this, recompile and test again and you should now receive the Token property set correctly.
If you regenerate the web service code, this change will of course get replaced and you will have to re-do it unless PayPal fixes this. BTW, my WSDL Version number is 98.0 at this time.
Gary Davis
I have multiple messages in SQS. The following code always returns only one, even if there are dozens visible (not in flight). setMaxNumberOfMessages I thought would allow multiple to be consumed at once .. have i misunderstood this?
CreateQueueRequest createQueueRequest = new CreateQueueRequest().withQueueName(queueName);
String queueUrl = sqs.createQueue(createQueueRequest).getQueueUrl();
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(queueUrl);
receiveMessageRequest.setMaxNumberOfMessages(10);
List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages();
for (Message message : messages) {
// i'm a message from SQS
}
I've also tried using withMaxNumberOfMessages without any such luck:
receiveMessageRequest.withMaxNumberOfMessages(10);
How do I know there are messages in the queue? More than 1?
Set<String> attrs = new HashSet<String>();
attrs.add("ApproximateNumberOfMessages");
CreateQueueRequest createQueueRequest = new CreateQueueRequest().withQueueName(queueName);
GetQueueAttributesRequest a = new GetQueueAttributesRequest().withQueueUrl(sqs.createQueue(createQueueRequest).getQueueUrl()).withAttributeNames(attrs);
Map<String,String> result = sqs.getQueueAttributes(a).getAttributes();
int num = Integer.parseInt(result.get("ApproximateNumberOfMessages"));
The above always is run prior and gives me an int that is >1
Thanks for your input
AWS API Reference Guide: Query/QueryReceiveMessage
Due to the distributed nature of the queue, a weighted random set of machines is sampled on a ReceiveMessage call. That means only the messages on the sampled machines are returned. If the number of messages in the queue is small (less than 1000), it is likely you will get fewer messages than you requested per ReceiveMessage call. If the number of messages in the queue is extremely small, you might not receive any messages in a particular ReceiveMessage response; in which case you should repeat the request.
and
MaxNumberOfMessages: Maximum number of messages to return. SQS never returns more messages than this value but might return fewer.
There is a comprehensive explanation for this (arguably rather idiosyncratic) behaviour in the SQS reference documentation.
SQS stores copies of messages on multiple servers and receive message requests are made to these servers with one of two possible strategies,
Short Polling : The default behaviour, only a subset of the servers (based on a weighted random distribution) are queried.
Long Polling : Enabled by setting the WaitTimeSeconds attribute to a non-zero value, all of the servers are queried.
In practice, for my limited tests, I always seem to get one message with short polling just as you did.
I had the same problem. What is your Receive Message Wait Time for your queue set to? When mine was at 0, it only returned 1 message even if there were 8 in the queue. When I increased the Receive Message Wait Time, then I got all of them. Seems kind of buggy to me.
I was just trying the same and with the help of these two attributes setMaxNumberOfMessages and setWaitTimeSeconds i was able to get 10 messages.
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(myQueueUrl);
receiveMessageRequest.setMaxNumberOfMessages(10);
receiveMessageRequest.setWaitTimeSeconds(20);
Snapshot of o/p:
Receiving messages from TestQueue.
Number of messages:10
Message
MessageId: 31a7c669-1f0c-4bf1-b18b-c7fa31f4e82d
...
receiveMessageRequest.withMaxNumberOfMessages(10);
Just to be clear, the more practical use of this would be to add to your constructor like this:
ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(queueUrl).withMaxNumberOfMessages(10);
Otherwise, you might as well just do:
receiveMessageRequest.setMaxNumberOfMessages(10);
That being said, changing this won't help the original problem.
Thanks Caoilte!
I faced this issue also. Finally solved by using long polling follow the configuration here:
https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-configure-long-polling-for-queue.html
Unfortunately, to use long polling, you must create your queue as FIFO one. I tried standard queue with no luck.
And when receiving, need also set MaxNumberOfMessages. So my code is like:
ReceiveMessageRequest receive_request = new ReceiveMessageRequest()
.withQueueUrl(QUEUE_URL)
.withWaitTimeSeconds(20)
.withMaxNumberOfMessages(10);
Although solved, still feel too wired. AWS should definitely provide a more neat API for this kind of basic receiving operation.
From my point, AWS has many many cool features but not good APIs. Like those guys are rushing out all the time.
For small task list I use FIFO queue like stackoverflow.com/a/55149351/13678017
for example modified AWS tutorial
// Create a queue.
System.out.println("Creating a new Amazon SQS FIFO queue called " + "MyFifoQueue.fifo.\n");
final Map<String, String> attributes = new HashMap<>();
// A FIFO queue must have the FifoQueue attribute set to true.
attributes.put("FifoQueue", "true");
/*
* If the user doesn't provide a MessageDeduplicationId, generate a
* MessageDeduplicationId based on the content.
*/
attributes.put("ContentBasedDeduplication", "true");
// The FIFO queue name must end with the .fifo suffix.
final CreateQueueRequest createQueueRequest = new CreateQueueRequest("MyFifoQueue4.fifo")
.withAttributes(attributes);
final String myQueueUrl = sqs.createQueue(createQueueRequest).getQueueUrl();
// List all queues.
System.out.println("Listing all queues in your account.\n");
for (final String queueUrl : sqs.listQueues().getQueueUrls()) {
System.out.println(" QueueUrl: " + queueUrl);
}
System.out.println();
// Send a message.
System.out.println("Sending a message to MyQueue.\n");
for (int i = 0; i < 4; i++) {
var request = new SendMessageRequest()
.withQueueUrl(myQueueUrl)
.withMessageBody("message " + i)
.withMessageGroupId("userId1");
;
sqs.sendMessage(request);
}
for (int i = 0; i < 6; i++) {
var request = new SendMessageRequest()
.withQueueUrl(myQueueUrl)
.withMessageBody("message " + i)
.withMessageGroupId("userId2");
;
sqs.sendMessage(request);
}
// Receive messages.
System.out.println("Receiving messages from MyQueue.\n");
var receiveMessageRequest = new ReceiveMessageRequest(myQueueUrl);
receiveMessageRequest.setMaxNumberOfMessages(10);
receiveMessageRequest.setWaitTimeSeconds(20);
// what receive?
receiveMessageRequest.withMessageAttributeNames("userId2");
final List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages();
for (final Message message : messages) {
System.out.println("Message");
System.out.println(" MessageId: "
+ message.getMessageId());
System.out.println(" ReceiptHandle: "
+ message.getReceiptHandle());
System.out.println(" MD5OfBody: "
+ message.getMD5OfBody());
System.out.println(" Body: "
+ message.getBody());
for (final Entry<String, String> entry : message.getAttributes()
.entrySet()) {
System.out.println("Attribute");
System.out.println(" Name: " + entry
.getKey());
System.out.println(" Value: " + entry
.getValue());
}
}
Here's a workaround, you can call receiveMessageFromSQS method asynchronously.
bulkReceiveFromSQS (queueUrl, totalMessages, asyncLimit, batchSize, visibilityTimeout, waitTime, callback) {
batchSize = Math.min(batchSize, 10);
let self = this,
noOfIterations = Math.ceil(totalMessages / batchSize);
async.timesLimit(noOfIterations, asyncLimit, function(n, next) {
self.receiveMessageFromSQS(queueUrl, batchSize, visibilityTimeout, waitTime,
function(err, result) {
if (err) {
return next(err);
}
return next(null, _.get(result, 'Messages'));
});
}, function (err, listOfMessages) {
if (err) {
return callback(err);
}
listOfMessages = _.flatten(listOfMessages).filter(Boolean);
return callback(null, listOfMessages);
});
}
It will return you an array with a given number of messages