Email multiple recipients without revealing other recipients - java

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.

Related

Using spring boot & parallel streams to send emails

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]))

Cannot send SMTP mail from AWS EC2

I am trying to send an email using SMTP.
It works fine in my local. But it does not work when i built it on AWS EC2 server.
This is my code to config and send email!
Any idea for me?
try{
Properties props = System.getProperties();
props.put("mail.smtp.starttls.enable",true);
props.put("mail.smtp.host","smtp.gmail.com");
props.put("mail.smtp.user","test#gmail.com");
props.put("mail.smtp.password","testpassword");
props.put("mail.smtp.port","587");
props.put("mail.smtp.auth",true);
props.put("mail.smtp.ssl.trust", "*");
String[] to = {toEmail};
Session session = Session.getDefaultInstance(props, null);
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress("test#gmail.com"));
InternetAddress[] toAddress = new InternetAddress[to.length];
// To get the array of addresses
for( int i=0; i < to.length; i++ ) { // changed from a while loop
toAddress[i] = new InternetAddress(to[i]);
}
System.out.println("EMAIL TO:"+toEmail);
for( int i=0; i < toAddress.length; i++) { // changed from a while loop
message.addRecipient(Message.RecipientType.TO, toAddress[i]);
}
message.setSubject(subject);
message.setText(content);
Transport transport = session.getTransport("smtp");
transport.connect("smtp.gmail.com","test#gmail.com","testpassword");
transport.sendMessage(message, message.getAllRecipients());
transport.close();
}
catch(Exception ex){
log.debug("send Email failed", ex);
}
AWS EC2 does not allow normal use of port 25 - the SMTP port.
It is severely throttled.
If you make very very light use of it then you might see sending email off the AWS account working occassionally. But generally it is not reliable
To resolve this problem there are two options
use AWS SES simple email service. Or SNS for some really simple use cases
ask AWS support to remove the restriction https://aws-portal.amazon.com/gp/aws/html-forms-controller/contactus/ec2-email-limit-rdns-request
We were recently bit by this issue as well. AWS by default throttles the number of connections that can originate from ec2 instances. The limitation is part of the EC2 service itself. Ironically it doesn't show any mention of this as a "limit" under the limits section of the EC2 service. It is mentioned on the form though to have this limit removed from your account:
I'm having trouble sending email over port 25 of my Amazon Elastic Compute Cloud (Amazon EC2) instance, or I'm getting frequent timeout errors. How do I remove the port 25 throttle on my EC2 instance?
It's also mentioned on the AWS Service Limits page for EC2:
The removal can be done in minutes once you submit the form to AWS.
References
How do I remove the throttle on port 25 from my EC2 instance?
Amazon Elastic Compute Cloud (Amazon EC2) Limits

how resolve Address Invalid exception

We tried to send mail using javax.mail. While sending mails we got following exception:
**sendMail - Message Sending Failed: Invalid Addresses;
nested exception is:
javax.mail.SendFailedException: 550 #5.1.0 Address rejected.2013-02-28 13:17:08,236**
What might be the problem?
It means that the receiving server does not recognise the mailbox (the part before the '#') of the e-mail address. It could be that it was misspelled, that it is simply a non-existing name, or it could even be that the receiving server was set to reject a message (e.g. spam) by replying with code 550.
Here is one of many pages that summarises the SMTP reply codes, and gives links to various relevant RFCs: http://www.greenend.org.uk/rjk/tech/smtpreplies.html.
EDIT: I need a bit more space to answer your question than the comments allow.
#RaghuKing, if you look at the Javadoc for javax.mail.SendFailedException, you will notice that you can call 3 methods on such an exception object (inside the catch block):
getInvalidAddresses() to get an array of addresses that are invalid and thus not sent to,
getValidSentAddresses() to get an array of addresses to which this message was sent succesfully, and
getValidUnsentAddresses() to get an array of addresses that are valid but to which the message was not sent to.
(Obviously, if one sends a message to multiple recipients, some may succeed and some fail, but the exception is thrown if there is at least one failure, regardless of how many successes. Obviously also if you are sending to only one address, you will have that one address in only one of these arrays, and it will probably NOT be in the ValidSent list.
These arrays will give you more information how to handle the exception, depending of the type of array an address is in. This will obviously depend on you application, but these might be reasonable suggestions:
Invalid Addresses: tell the user that the message was not sent because the address was wrong, for each invalid address in the list, and provide a way to correct the address, then try to resend to the correct address (or cancel if the user does not provide a different address);
Valid Sent Addresses: Don't resend;
Valid Unsent Addresses: Try to resend to these addresses. Sending probably stopped before getting to these addresses because of a previous incorrect address.
But in the end it is you who has to apply common sense, and perhaps experiment a little with the functions you don't understand until you understand them.
This code can print logs for invalid address(es):
try {
sender.send(message);
}catch (MailSendException me){
detectInvalidAddress(me);
}
private void detectInvalidAddress(MailSendException me) {
Exception[] messageExceptions = me.getMessageExceptions();
if (messageExceptions.length > 0) {
Exception messageException = messageExceptions[0];
if (messageException instanceof SendFailedException) {
SendFailedException sfe = (SendFailedException) messageException;
Address[] invalidAddresses = sfe.getInvalidAddresses();
StringBuilder addressStr = new StringBuilder();
for (Address address : invalidAddresses) {
addressStr.append(address.toString()).append("; ");
}
logger.error("invalid address(es):{}", addressStr);
return;
}
}
logger.error("exception while sending mail.", me);
}
Had experienced this same exception .I realized that i could not send email to unknown users . After consulting , i found out that our SMTP server was not an open mail relay server read Open mail Relay.

SMPP Invalid destination address submitting international message

Good day guys!. I'm having a problem trying to submit an international sms vía SMPP (using Logica Java library). I'm gonna summarize the tests I've done. I'm using WireShark to monitor SMPP related activities.
(Working)
//Connect and stablish session
Connection conn = new TCPIPConnection(providerAddress, port);
Session session = new Session(conn);
BindRequest breq = new BindTransmitter();
breq.setSystemId(user);
breq.setPassword(pass);
breq.setSystemType("CMT");
breq.setInterfaceVersion((byte)34);
breq.setAddressRange((byte)0x01, (byte)0x01,null);
Response resp = session.bind(breq);
//Create message
SubmitSM msg = new SubmitSM();
msg.setDestAddr((byte)1, (byte)1, "58412014XXXX");
msg.setSourceAddr((byte)1, (byte)1, "58412014XXXX");
msg.setShortMessage("Test from tedexis","ISO-8859-1");
//Here we submit message
session.submit(msg);
//Disconnect
session.unbind();
Result: Message is delivered correctly. Here we validate credentials are valid, and notice the source and destination addresses are the same
(Failing) The code remains the same except for the message destination address which is now set for an INTERNATIONAL PHONE NUMBER
msg.setSourceAddr((byte)1, (byte)1, "1321237XXXX");
Result: Fails, checking WireShark I observe the following exception during the submit:
SMPP Submit_sm - resp: "Invalid destination address"
We may think that our credentials are not valid for international deliveries but we are currently using these credentials delivering international messages through their webservice interface.
I must be missing a configuration setting or wrongly setting one already, but I ran out of ideas, if anyone can point me in the right direction I would be glad.
First, you dont have to set your address range since you're binding as a transmitter, because the address range is used to inform the SMSC that this 'receiver' session will handle MO messages from the desired address range.
As for sending to international numbers, i'm not into logica's API but i'm pretty sure that you're missing to set the destination address ton to 1 (international number) and the destination address npi to 0 (Unknown) or 1 (ISDN) and retry the sending.
If the error persists, you'll have to call your provider, it is possible that they gave you the permission to send to international numbers through webservice only.

Java mail bounced back mail's address

I have to send messages to many clients. But many of them bounce back. I want a list of those email addresses. How can I get that list from my Java application?
Make a special email address bounced#yourdomain.com where you will capture all bounced emails for analysis.
Add the following header to your sent emails:
Return-Path: <bounced#yourdomain.com>
Now the emails are going to bounce back to that address.
Read emails at that address from your java program from time to time, for example via IMAP (or depending on your server via a notification interface/whatever), and when you see an email address record it in your database
Note that if you are doing a newsletter app, you should not blacklist the email from the first time, but make count it's bounces, and blacklist it after 3-4 bounces (some people set their email to bounce when they go in vacation and such, so they need special taking care of).
I solve this question using
SMTPMessage msg = new SMTPMessage(getSession());
msg.setEnvelopeFrom(bounceAddr);
Please see the javamail doc and see it:
void com.sun.mail.smtp.SMTPMessage.setEnvelopeFrom(String from)
Set the From address to appear in the SMTP envelope. Note that this is different than the From address that appears in the message itself. The envelope From address is typically used when reporting errors. See RFC 821 for details.
If set, overrides the mail.smtp.from property.
Parameters:
from the envelope From address

Categories

Resources