Using spring boot & parallel streams to send emails - java

I am trying to send email using spring-boot but send it using parallel streams so that it is not synchronized.
Can anyone point me in the right direction with code.
This is what I have so far -
for (String toAddress : emailDto.getToEmailAddresses()) {
message = new SimpleMailMessage();
message.setTo(toAddress);
message.setSubject(emailDto.getSubject());
message.setText(emailDto.getBody());
message.setFrom(fromAddress);
emailSender.send(message);
_logger.info("Send Email successfully to " + toAddress);
}
I am trying to do something along these lines-
toAddresses.parallelStream().forEach(System.out::println);
But use parallel stream to send each email.

SimpleMailMessage.setTo already has the case for multiple addresses so you could simply write
message.setTo(emailDto.getToEmailAddresses().toArray(new String[0]))

Related

Smack send and receive message without chat

I would like to send a simple message from one client to another one not opening a chat because there will never be a response and all messages fire the same event.
In the smack (4.1.7) documentation I found out that it is possible to do so but so far I did not find a way how to do it.
Do you have any ideas how to do it?
Would it be better (especially acording to performance: runtime and memory) to use the chat?
For receiving you'd probably want to use a synchronous stanza listener with a suitable filter.For example, if you want to receive messages with a body from user#example.org, then you could
XMPPConnection connection = …;
connection.addSyncStanzaListener(new StanzaListener() {
#Override
void process(Stanza stanza) {
Message message = (Message) stanza;
// Received new message with body from user#example.org
}, new AndFilter(MessageWithBodiesFilter.INSTANCE,
FromMatchesFilter.create("user#example.org")));
Sending messages is even easier
Message message = new Message("user#example.org", "Hi, how are you?");
XMPPConnection connection = …;
connection.sendStanza(message);
Hint: Reading the source code of Smack is a great way to learn about such stuff. If you look at the source of ChatManager, you will find what I've just written above.

SMSLib sending message, using multiple gateways

I'm using SMSLib for sending and receiving messages. Everything's working great, but now I'd like to plug more than one modem. I want to receive messages by all of my modems and do something with them (I can do that, I think). I also want to send messages, but only through the selected modem (there's my problem). Until I had one gateway i did sending like this:
OutboundMessage msg = new OutboundMessage(recipientNumber, text);
Service.getInstance().sendMessage(msg);
But now, how can I select the one specific gateway, that I want to use to send my message?
I found a topic with a problem a bit like mine, but not exactly:
Use multiple gateway with SMSLIB
Each modem is a AGatway object in SMSLib so you need to set it up first:
SerialModemGateway modemGateway = new SerialModemGateway("FirstGateway", "/dev/ttyM0", "9600", "WAVECOM", "Fastrack");
Service.getInstance().addGateway(modemGateway);
Where FirstGateway is ID of your modem which is called gatewayId in SMSLib. All you have to do now is pass your gatewayId to sendMessage method or queueMessage (if you send messages asynchronously):
OutboundMessage msg = new OutboundMessage(recipientNumber, text);
Service.getInstance().sendMessage(msg, "FirstGateway");
or:
OutboundMessage msg = new OutboundMessage(recipientNumber, text);
msg.setGatewayId("FirstGateway");
Service.getInstance().sendMessage(msg);
I didnt notice that there is such a method sendMessage() which takes gatewayId as a second agrument. If so, there will be perfect. I'll check that tomorrow, are you sure about that? I'm using SmsLib 3.x
EDIT:
It's exactly as you said. I just put gatewayId as a second argument and it's working. Another options is that you can set gatewayId of created OutboundMessage:
OutboundMessage msg = new OutboundMessage(recipientNumber, text);
msg.setGatewayId("FirstGateway");
Service.getInstance().sendMessage(msg);
So easy.. Thanks!
I would't use sendMessage method with multiple gateways, use queueMessage it adds your msg to SMSLib service queue and sends it asynchronously.
Also , if you start your application with:
-Dsmslib.queuedir=yourQueuedMessagesDirectory
you will be able to store all unsent messages on hard drive and give SMSLib service facility to send them after application restart.

Converting JMS Message to IBM PCF

I am in a bit of a bind. I am trying to read a message of a WMQ via jms and then convert it to a pcf message for processing. I have only been able to find one resource on this and it hasn't been very helpful [bottom of http://www-01.ibm.com/support/docview.wss?uid=swg21395682 ]
I have tried to implement the technique in the above doc but every time I get to line
PCFMessage response = new PCFMessage(dataInput);
I throw MQRC 3013 - MQRCCF_STRUCTURE_TYPE_ERROR
This is the way my code looks, maybe you can see something I don't.
BytesMessage message = null;
do {
// The consumer will wait 10 seconds (10,000 milliseconds)
message = (BytesMessage) myConsumer.receive(10000);
// get the size of the bytes message & read into an array
int bodySize = (int) message.getBodyLength();
byte[] data = new byte[bodySize];
message.readBytes(data, bodySize);
// Read into Stream and DataInput Stream
ByteArrayInputStream bais = new ByteArrayInputStream(data);
DataInput dataInput = new DataInputStream(bais);
// Pass to PCF Message to process
//MQException.logExclude(new Integer(2079));
PCFMessage qStatsPcf = new PCFMessage(dataInput);
session.commit();
if (message != null) {
processMessage(qStatsPcf);
}
} while (message != null);
myConsumer.close();
A couple updates in response to T.Rob's answer.
I am currently running MQ 7.0. This is a what it is type thing, I can't currently upgrade.
As to what I am trying to do, I am pulling messages from SYSTEM.ADMIN.STATISTICS.QUEUE and I want to parse that information for auditing purposes. The reasoning behind converting to a PCF message is that I am looking to pull some PCF parameters from these messages - for example .getParameter(PCFConstants.MQIAMO_PUTS)
I am not attempting to send messages to MQ in anyway, just pull messages off and process them.
A couple problems with this question:
There is no mention of the version of the version of MQ jms client that is in use. Since IBM has repackaged the Java/JMS classes several times, it is necessary to mention which version you are working with to get a better answer.
It is unclear what it is you are trying to do. An MQ PCF message is processed by the MQ Command Server. The messages are a binary format consisting of a linked list of name/type/value tuples. If your message body is not already in PCF name/type/value format, then casting it as a PCF message is expected to fail.
Since it is not possible to respond to the question as worded with a solution, I'll provide some recommendations based on wild guesses as to what it is you might be trying to do.
Use a modern MQ client. The Technote you linked to is for out-of-support versions of MQ client. You want one that is at least MQ v7.1, but preferably v8.0. since any version of MQ client works with any version of MQ, use the version that is most current. Just remember, the functionality you get is based on the oldest version of MQ used at the client or server. A v8.0 client doesn't get you v8.0 function on a v7.0 QMgr. Go to the SupportPacs page and look for entries with names like MQC**. The MQ v8.0 client is current and it is SupportPac MQC8.
If you really are trying to submit PCF messages to MQ's command processor, instantiate a PCF Agent to do it. Then construct the PCF message using one of the PCF message constructors that lets you specify the selectors and their values.
What happened when you tried using the PCF Java samples? Did they also fail? Did they work? If so, how does your code differ? You did look at IBM's PCF samples, right? Please see Installation directories for samples for the location for the sample programs, including the PCF samples.
If you are not attempting to send messages to the MQ Command Processor, please update the question to let us know what it is you are trying to do and why you believe you need PCF messages to do it.
my 2 cents...
Why are you using JMS to retrieve PCF Messages?
MQ Java is best placed to handle all statistics and event message. My suggestion is go with MQQueueManager object and retrieve a MQMessage out of SYSTEM.ADMIN.STATISTICS.QUEUE and pass it to PCFMessage constructor.
I have not compiled or tested the following, but it gives an outline.
//no try catch block to keep it simple
//assumed MQQueueManager (qmgr object) is already created
//assumed statQueue is available through qmgr.accessQueue() method
do {
MQMessage message = new MQMessage();
//gmo as CMQC.MQGMO_FAIL_IF_QUIESCING | CMQC.MQGMO_WAIT | CMQC.MQGMO_SYNCPOINT | CMQC.MQGMO_CONVERT;
message = statQueue.get(message, gmo);
// Pass to PCF Message to process
PCFMessage qStatsPcf = new PCFMessage(message);
qmgr.commit();
if (message != null) {
processMessage(qStatsPcf);
}
} while (message != null);
statQueue.close();
qmgr.close();

E-mail sent with commons-mail is *sometimes* not received. How can I troubleshoot?

When I send out an e-mail and it isn't received, how can I figure out what the cause of the problem is?
My app sends e-mails through SMTP using the Apache commons-mail library. For testing purposes, I am using the gmail SMTP server. (Our production app uses an internal server on our network).
In one case on the test server, I have a batch job that generates 5 e-mails with attachments. Some e-mails are received and others are marked as sent, but never appear in my inbox. There doesn't seem to be a pattern to which e-mails are received and which ones silently vanish.
The code that sends and checks for errors looks like this:
final Mail mail = ...;
//The Mail class is our app's mail object, which provides data used to generate the MIME e-mail and record the results.
final MultiPartEmail email = ...;
try {
email.setSentDate(mail.getDateSent());
email.send();
}
catch (EmailException ee) {
success = false;
mail.setDateSent(null);
getLog().error("Mail not sent: ", ee);
if (ee.getMessage().indexOf("receiver address required") != -1) {
mail.setErrorMessage(ee.getMessage());
getLog().error(mail.toString());
}
}
In the debugger, I determine that no exception is thrown.
My first guess was that the attachment size is too large; but, gmail supposedly supports 25MB attachments, and my largest attachment is 14.3 MB. In some cases when I run the entire batch of 5 e-mails, the e-mail with the largest attachment gets through, and the smaller ones disappear.

Email multiple recipients without revealing other recipients

I'm using javamail to send emails to a list of recipients, but don't want them to be able to see who else received the email. I also don't want to send it using BCC since then the user doesn't even see themselves in the TO list. I thought this code would do it, but it shows all the recipients in the TO list. Other than creating a loop and sending the emails one at a time, is there another way to do this?
(NOTE: recipients[] is a string array containing the email addresses.)
javax.mail.internet.InternetAddress[] addressTo = new javax.mail.internet.InternetAddress[recipients.length];
for (int i = 0; i < recipients.length; i++)
{
addressTo[i] = new javax.mail.internet.InternetAddress(recipients[i]);
}
msg.setRecipients(javax.mail.Message.RecipientType.TO, addressTo);
No, there isn't a way to do this with email.
You have to explicitly build and send an email iterating by each of your recipients, one of them as the sole member of your addressTo array.
The SMTP protocol doesn't care who's listed in the message and the recipients specified on the RCPT TO command are only used to figure out who to transport the message to. There's nothing stopping you from building the RFC822 message with the To header as you've defined above and then writing a custom SMTP client that send your particular message out but with a different set of recipients. And just because you can send the message doesn't mean a spam filter along the way is going to notice the wonky recipient headers and block the message.
In my experience, JavaMail's SMTP client is really good at sending basic messages without any of the mail tricks you often seen used by mailing list providers and spammers. Those companies spend a lot of effort to make sure they can send messages the way they want but they also are in a constant fight to make sure they're messages are treated as legit email.
Short answer: I'd resort to BCC and if this is for marketing purposes, consider using a company that specializes in this kind of thing.
Why are you concerned about the recipient not seeing his own address? He already knows his his own address, so why is it an issue? BCC was designed to handle exactly the problem you describe. It's been around for decades & sounds like a perfect fit.
Actually, we don't have to manually create InternetAddress objects for Multi Recepients.
InternetAddress api provides a parse() method to do this for us.
Sample code for this is as below,
msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toAddress));
Here parse method creates multiple InternetAddress objects if toAddress contains multiple email addresses seperated by ,(comma).
Check for below API for more details.
http://docs.oracle.com/javaee/6/api/javax/mail/internet/InternetAddress.html#parse(java.lang.String)
Happy Coding. :)
as Message.RecipientType you should use Message.RecipientType.BCC to not showing the every address to every recipient
Google Keywords: Java Mail BCC
Try this:
Session session = Session.getInstance(properties);
Transport transport = session.getTransport("smtp");
String recipient = "ex1#mail.com,ex2#mail.";
String[] recipients = recipient.split(",");
transport.connect(server, username, password);
for (String to : recipients) {
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
InternetAddress[] address = {new InternetAddress(to)};
message.setRecipients(Message.RecipientType.TO, address);
message.setSubject(subject);
message.setText(body);
message.setContent(body, "text/plain");
message.saveChanges();
transport.sendMessage(message, address);
}
transport.close();
According to the documentation for javax.mail.Transport:
public static void send(Message msg,
Address[] addresses)
throws MessagingException
Send the message to the specified addresses, ignoring any recipients specified
in the message itself.
So you should be able to put the actual delivery addresses (RCPT TO addresses) in the array argument to Transport.send, while putting whatever you want the recipients to see in the message headers via Message.setRecipient, MIMEMessage.addHeader, etc.
If you want different sets of users to see different things, you will have to construct and send a separate message for each set.
You can do this by setting the code as below
message.setRecipients(Message.RecipientType.BCC, toAddrs);
instead of
message.setRecipients(Message.RecipientType.TO, toAddrs);
Place your session creation inside the loop. It will create the session for every user but
it's time complex.

Categories

Resources