Mail repeatedly sent by JavaMail ends up in Spam folder - java

I'm sending a mail using JavaMail from inside a JSP page as follows:
String from= request.getParameter("from");
String to= request.getParameter("to");
String thanks= request.getParameter("thanks");
String subject= request.getParameter("subject");
try{
SmtpClient client = new SmtpClient("smtp.example.com");
client.from(from);
client.to(to);
PrintStream message = client.startMessage();
message.println("From: " + from);
message.println("To: " + to);
message.println("Subject: " + subject);
message.println();
Enumeration paramNames = request.getParameterNames();
while(paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
String paramValue = request.getParameter(paramName);
if (request.getParameter(paramName) != null &&
request.getParameter(paramName) != "") {
message.println(paramName + ": " + paramValue);
message.println();
}
}
client.closeServer();
}
catch (IOException e){
System.out.println("ERROR IN DELIVERING THE FORM:"+e);
}
This was working fine first and sent the data to my Inbox, but after many trials and insignificant changes, now the post goes to my Spam folder.
I appreciate if anyone could tell me where the problem is and what causes this.

Mail goes to spam when Google find any insecure IP or links, Make sure you don't have any other IP which is not authenticated (can be access by https://"IP")

What causes this? Your spam filter!
Depending on what you/your mail provider uses as spam filter, you might learn something from the mail headers - I recall spamassassin giving some information about what filter scored how high, and the resulting spam score. Others might do that as well.
You might also be able to train your spam filter to recognize this mail as non-spam (ham) if you remove it from the spamfolder.

If there is overflow emailId then most of the times it goes to spam, It's done by google. But you can still change that protocol by google by below method:
First time you need to go to your spam and open the mail then the cross option would be above the mail (Which means cancel that mail from spam) click on that (mentioned in the screenshot:.
From the next time, it would not go to your spam.

Related

How to send email with sender name using AWS SDK?

I am currently using AWS SDK to send mails:
// from: noreply#domain.com
public void sendMail(String from, String to, String subject, String htmlBody) {
LOGGER.info(String.format("Sending Mail from: %s, to: %s, with subject: %s", from, to, subject));
try {
AWSCredentials credentials = new BasicAWSCredentials(awsAccessKey, awsSecret);
AmazonSimpleEmailService client = AmazonSimpleEmailServiceClientBuilder.standard()
.withRegion(Regions.AP_SOUTH_1).withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
SendEmailRequest request = new SendEmailRequest().withDestination(new Destination().withToAddresses(to))
.withMessage(new Message()
.withBody(new Body().withHtml(new Content().withCharset("UTF-8").withData(htmlBody)))
.withSubject(new Content().withCharset("UTF-8").withData(subject)))
.withSource(from);
client.sendEmail(request);
} catch (Exception e) {
LOGGER.error(String.format("Error while sending email: %s", e.getMessage()));
throw new IllegalArgumentException(MessageEnum.FAILED_TO_SEND_AN_EMAIL.name());
}
}
The method works fine but the email is sent as:
But I am expecting the email to be sent with the sender name so that it can be displayed like:
Does anyone have any idea on how to send an email including the sender name? Any help is appreciated.
If you check documentation of SendEmailRequest you can find out that it supports standard way to define friendly name in email:
source - The email address that is sending the email. This email address must be either individually verified with Amazon SES, or from a domain that has been verified with Amazon SES. For information about verifying identities, see the Amazon SES Developer Guide.
If you are sending on behalf of another user and have been permitted to do so by a sending authorization policy, then you must also specify the SourceArn parameter. For more information about sending authorization, see the Amazon SES Developer Guide.
Amazon SES does not support the SMTPUTF8 extension, as described in RFC6531. For this reason, the local part of a source email address (the part of the email address that precedes the # sign) may only contain 7-bit ASCII characters. If the domain part of an address (the part after the # sign) contains non-ASCII characters, they must be encoded using Punycode, as described in RFC3492. The sender name (also known as the friendly name) may contain non-ASCII characters. These characters must be encoded using MIME encoded-word syntax, as described in RFC 2047. MIME encoded-word syntax uses the following form: =?charset?encoding?encoded-text?= .
So that string should look like:
John Doe <johndoe#example.com>
InternetAddress can be used for this, but you need to pay attention on encoding restrictions that SendEmailRequest has for from argument
request.withSource((new InternetAddress("mail#example.com", "Your Name")).toString());
You are using an old Amazon Simple Email Service API (V1). For best practice, use the SES Java V2 API. V2 packages always start with software.amazon...
The Amazon SDK team strongly recommends moving from V1 to V2:
The AWS SDK for Java 2.x is a major rewrite of the version 1.x code base. It’s built on top of Java 8+ and adds several frequently requested features. These include support for non-blocking I/O and the ability to plug in a different HTTP implementation at run time.
You can set this information (sender name) by setting the SendEmailRequest object properly.
Here is the Java V2 SES example.
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ses.SesClient;
import software.amazon.awssdk.services.ses.model.*;
import software.amazon.awssdk.services.ses.model.Message;
import software.amazon.awssdk.services.ses.model.Body;
import javax.mail.MessagingException;
public class SendMessageEmailRequest {
public static void main(String[] args) {
final String USAGE = "\n" +
"Usage:\n" +
" <sender> <recipient> <subject> \n\n" +
"Where:\n" +
" sender - an email address that represents the sender. \n"+
" recipient - an email address that represents the recipient. \n"+
" subject - the subject line. \n" ;
if (args.length != 3) {
System.out.println(USAGE);
System.exit(1);
}
String sender = "foo#testmail.com" ;//args[0];
String recipient = "foo#testmail.com" ;//args[1];
String subject = "Test Email"; //args[2];
Region region = Region.US_EAST_1;
SesClient client = SesClient.builder()
.region(region)
.build();
// The email body for non-HTML email clients
String bodyText = "Hello,\r\n" + "See the list of customers. ";
// The HTML body of the email
String bodyHTML = "<html>" + "<head></head>" + "<body>" + "<h1>Hello!</h1>"
+ "<p> See the list of customers.</p>" + "</body>" + "</html>";
try {
send(client, sender, recipient, subject, bodyText, bodyHTML);
client.close();
System.out.println("Done");
} catch (MessagingException e) {
e.getStackTrace();
}
}
public static void send(SesClient client,
String sender,
String recipient,
String subject,
String bodyText,
String bodyHTML
) throws MessagingException {
Destination destination = Destination.builder()
.toAddresses(recipient)
.build();
Content content = Content.builder()
.data(bodyHTML)
.build();
Content sub = Content.builder()
.data(subject)
.build();
Body body = Body.builder()
.html(content)
.build();
Message msg = Message.builder()
.subject(sub)
.body(body)
.build();
SendEmailRequest emailRequest = SendEmailRequest.builder()
.destination(destination)
.message(msg)
.source(sender)
.build();
try {
System.out.println("Attempting to send an email through Amazon SES " + "using the AWS SDK for Java...");
client.sendEmail(emailRequest);
} catch (SesException e) {
System.err.println(e.awsErrorDetails().errorMessage());
System.exit(1);
}
}
}

Downloading attachments from unseen messages

I work on university project in java. I have to download attachments from new emails using GMAIL API.
I successfully connected to gmail account using OAuth 2.0 authorization.
private static final List<String> SCOPES = Collections.singletonList(GmailScopes.GMAIL_READONLY);
I tried to get unseen mails using
ListMessagesResponse listMessageResponse = service.users().messages().list(user).setQ("is:unseen").execute();
listMessageResponse is not null but when I call method .getResultSizeEstimate() it returns 0
also I tried to convert listMessageResponse to List < Message > (I guess this is more usable) using
List<Message> list = listMessageResponse.getMessages();
But list launches NullPointerException
Then tried to get each attachment with
for(Message m : list) {
List<MessagePart> part = m.getPayload().getParts();
for(MessagePart p: part) {
if(p.getFilename()!=null && p.getFilename().length()>0) {
System.out.println(p.getFilename()); // Just to check attachment filename
}
}
}
Is my approach correct (if not how to fix it) and how should I download those attachments.
EDIT 1:
Fixed q parameter, I mistakenly wrote is:unseen instead of is:unread.
Now app reaches unread mails successfully.
(For example there was two unread mails and both successfully reached, I can get theirs IDs easy).
Now this part trows NullPointerException
List<MessagePart> part = m.getPayload().getParts();
Both messages have attachments and m is not null (I get ID with .getID())
Any ideas how to overcome this and download attachment?
EDIT 2:
Attachments Downloading part
for(MessagePart p : parts) {
if ((p.getFilename() != null && p.getFilename().length() > 0)) {
String filename = p.getFilename();
String attId = p.getBody().getAttachmentId();
MessagePartBody attachPart;
FileOutputStream fileOutFile = null;
try {
attachPart = service.users().messages().attachments().get("me", p.getPartId(), attId).execute();
byte[] fileByteArray = Base64.decodeBase64(attachPart.getData());
fileOutFile = new FileOutputStream(filename); // Or any other dir
fileOutFile.write(fileByteArray);
fileOutFile.close();
}catch (IOException e) {
System.out.println("IO Exception processing attachment: " + filename);
} finally {
if (fileOutFile != null) {
try {
fileOutFile.close();
} catch (IOException e) {
// probably doesn't matter
}
}
}
}
}
Downloading working like charm, tested app with different type of emails.
Only thing left is to change label of unread message (that was reached by app) to read. Any tips how to do it?
And one tiny question:
I want this app to fetch mails on every 10 minutes using TimerTask abstract class. Is there need for manual "closing" of connection with gmail or that's done automatically after run() method iteration ends?
#Override
public void run(){
// Some fancy code
service.close(); // Something like that if even exists
}
I don't think ListMessagesResponse ever becomes null. Even if there are no messages that match your query, at least resultSizeEstimate will get populated in the resulting response: see Users.messages: list > Response.
I think you are using the correct approach, just that there is no message that matches your query. Actually, I never saw is:unseen before. Did you mean is:unread instead?
Update:
When using Users.messages: list only the id and the threadId of each message is populated, so you cannot access the message payload. In order to get the full message resource, you have to use Users.messages: get instead, as you can see in the referenced link:
Note that each message resource contains only an id and a threadId. Additional message details can be fetched using the messages.get method.
So in this case, after getting the list of messages, you have to iterate through the list, and do the following for each message in the list:
Get the message id via m.getId().
Once you have retrieved the message id, use it to call Gmail.Users.Messages.Get and get the full message resource. The retrieved message should have all fields populated, including payload, and you should be able to access the corresponding attachments.
Code sample:
List<Message> list = listMessageResponse.getMessages();
for(Message m : list) {
Message message = service.users().messages().get(user, m.getId()).execute();
List<MessagePart> part = message.getPayload().getParts();
// Rest of code
}
Reference:
Class ListMessagesResponse
Users.messages: list > Response

Add embedded image in emails in AWS SES service

I am trying to write a Java app which can send emails to specify emails. In the email i also want to attach some pic.
Please find my code below :-
public class AmazonSESSample {
static final String FROM = "abc#gmail.com";
static final String TO = "def#gmail.com";
static final String BODY = "This email was sent through Amazon SES by using the AWS SDK for Java. hello";
static final String SUBJECT = "Amazon SES test (AWS SDK for Java)";
public static void main(String[] args) throws IOException {
Destination destination = new Destination().withToAddresses(new String[] { TO });
Content subject = new Content().withData(SUBJECT);
Message msg = new Message().withSubject(subject);
// Include a body in both text and HTML formats
//Content textContent = new Content().withData("Hello - I hope you're having a good day.");
Content htmlContent = new Content().withData("<h2>Hi User,</h2>\n"
+ " <h3>Please find the ABC Association login details below</h3>\n"
+ " <img src=\"logo.png\" alt=\"Mountain View\">\n"
+ " Click here to go to the association portal.\n"
+ " <h4>Association ID - 12345</h4>\n" + " <h4>Admin UID - suny342</h4>\n"
+ " <h4>Password - poass234</h4>\n" + " Regards,\n" + " <br>Qme Admin</br>");
Body body = new Body().withHtml(htmlContent);
msg.setBody(body);
SendEmailRequest request = new SendEmailRequest().withSource(FROM).withDestination(destination)
.withMessage(msg);
try {
System.out.println("Attempting to send an email through Amazon SES by using the AWS SDK for Java...");
AWSCredentials credentials = null;
credentials = new BasicAWSCredentials("ABC", "CDF");
try {
// credentialsProvider.
} catch (Exception e) {
throw new AmazonClientException("Cannot load the credentials from the credential profiles file. "
+ "Please make sure that your credentials file is at the correct "
+ "location (/Users/iftekharahmedkhan/.aws/credentials), and is in valid format.", e);
}
AmazonSimpleEmailService client = AmazonSimpleEmailServiceClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials)).withRegion("us-west-2").build();
client.sendEmail(request);
System.out.println("Email sent!");
} catch (Exception ex) {
System.out.println("The email was not sent.");
System.out.println("Error message: " + ex.getMessage());
}
}
}
The image is placed in the resource directory but it is not being embeded in the email. Can anyone please help.
Instead of relative path, you'll need to use either an absolute public path to the image itself or a data URL. For example:
<img src=\"https://example.com/logo.png\" alt=\"Mountain View\" />
or
<img src=\"data:image/png;base64, {BASE64_ENCODED_DATA}\" alt=\"Mountain View\" />
EDIT
As of January 2020, Gmail still does not support base64 encoded images.
The method posted by #sebagra works well.
In case of Python using boto3 and ses client, the way to set to set the Content-Disposition to inline is:
att.add_header('Content-ID', '<myImage>')
att.add_header('Content-Disposition', 'inline', filename=os.path.basename(IMAGE_PATH))
Full example based on the python example in the AWS docs:
import os
import boto3
from botocore.exceptions import ClientError
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
# Replace sender#example.com with your "From" address.
# This address must be verified with Amazon SES.
SENDER = "Sender Name <sender#example.com>"
# Replace recipient#example.com with a "To" address. If your account
# is still in the sandbox, this address must be verified.
RECIPIENT = "recipient#example.com"
# Specify a configuration set. If you do not want to use a configuration
# set, comment the following variable, and the
# ConfigurationSetName=CONFIGURATION_SET argument below.
CONFIGURATION_SET = "ConfigSet"
# If necessary, replace us-west-2 with the AWS Region you're using for Amazon SES.
AWS_REGION = "us-west-2"
# The subject line for the email.
SUBJECT = "Customer service contact info"
# The full path to the file that will be attached to the email.
IMAGE_PATH = "path/to/myImage.png"
# The email body for recipients with non-HTML email clients.
BODY_TEXT = "Hello,\r\nPlease see the attached file for a list of customers to contact."
# The HTML body of the email.
BODY_HTML = """\
<html>
<head></head>
<body>
<h1>Hello!</h1>
<p>Please see the attached file for a list of customers to contact.</p>
</body>
</html>
"""
# The character encoding for the email.
CHARSET = "utf-8"
# Create a new SES resource and specify a region.
client = boto3.client('ses',region_name=AWS_REGION)
# Create a multipart/mixed parent container.
msg = MIMEMultipart('mixed')
# Add subject, from and to lines.
msg['Subject'] = SUBJECT
msg['From'] = SENDER
msg['To'] = RECIPIENT
# Create a multipart/alternative child container.
msg_body = MIMEMultipart('alternative')
# Encode the text and HTML content and set the character encoding. This step is
# necessary if you're sending a message with characters outside the ASCII range.
textpart = MIMEText(BODY_TEXT.encode(CHARSET), 'plain', CHARSET)
htmlpart = MIMEText(BODY_HTML.encode(CHARSET), 'html', CHARSET)
# Add the text and HTML parts to the child container.
msg_body.attach(textpart)
msg_body.attach(htmlpart)
# Define the attachment part and encode it using MIMEApplication.
att = MIMEApplication(open(IMAGE_PATH, 'rb').read())
# Add a header to tell the email client to treat this part as an attachment,
# and set an id and content disposition.
att.add_header('Content-ID', '<myImage>')
att.add_header('Content-Disposition', 'inline', filename=os.path.basename(IMAGE_PATH))
# Attach the multipart/alternative child container to the multipart/mixed
# parent container.
msg.attach(msg_body)
# Add the attachment to the parent container.
msg.attach(att)
try:
response = client.send_raw_email(
Source=SENDER,
Destinations=[
RECIPIENT
],
RawMessage={
'Data': msg.as_string(),
}
)
# Display an error if something goes wrong.
except ClientError as e:
print(e.response['Error']['Message'])
else:
print("Email sent! Message ID:"),
print(response['MessageId'])
In case of using sesv2 the msg is built the same but the the api to use is send_email:
...
client = boto3.client('sesv2',region_name=AWS_REGION)
...
response = client.send_email(
FromEmailAddress=SENDER,
Destination={
'ToAddresses': [
RECIPIENT
]
},
Content={
'Raw': {
'Data': msg.as_string()
}
}
)
...
I was able to send an email using AWS SES with images that can be seen in the GMail client, by attaching the images to the message and using an inline disposition reference to them.
I used the code explained in the AWS docs to attach images to a MimeMessage, and then using the cid reference from the HTML to those images (as explained in this post answer).
First, we attach the images to the message adding a couple of specific attributes (Header and Disposition):
MimeMultipart msg = new MimeMultipart("mixed");
DataSource fds = new FileDataSource("/path/to/my/image.png");
att.setDataHandler(new DataHandler(fds));
att.setFileName(fds.getName());
att.setHeader("Content-ID","<myImage>");
att.setDisposition("inline; filename=\"image.png\"");
msg.addBodyPart(att);
Note that the < and > in the Content-ID attribute must be present enclosing whatever id you choose (myImage in my example).
Then, in the HTML of the message body we just need to add the cid (content id) of each image:
<img src="cid:myImage">
For the full code, I pretty much used the AWS reference above (using same variable names), the only changes made were the ones of the setHeader and setDisposition methods.
I had no trouble sending an inline base 64 image to a Yahoo account using AWS SES. When I tried to send to a GMail account I had trouble. The text I sent rendered, but the image didn't show.
I discovered that GMail wasn't stripping the image. It was just not displaying it. I confirmed this by selecting More -> "Show original" while viewing the message in GMail.

Sending Mail via commons-email-1.3.2

I have problem with ArrayList mailing again. Program building and working succesfully about 1 month. But today i detect some important mails not coming from my program. And I begin debugging my code. Let me share my findings.
I have a Arraylist populated from some DB queries;
ArrayList<String> importantlist = new ArrayList<String>();
When populating complete I send this Arraylist to Mail sender method;
if (importantlist.size() > 0) {
sendMail(importantlist);
}
sendMail method;
public void sendMail(ArrayList cominglist) throws Exception {
StringBuilder b = new StringBuilder();
for(Object coming: cominglist)
b.append(coming).append("\n");
String cominglistString = b.toString();
Email email = new SimpleEmail();
email.setHostName("hostname here");
email.setSmtpPort(587);
email.setAuthentication("mail sender user here","userpasswordhere");
email.setSSLOnConnect(false);
email.setFrom("mail sender address here");
email.setSubject("Example important list");
email.setMsg("Example important List body;\n"+cominglistString);
email.addTo("receiver user here");
email.addTo("receiver user here");
email.send();
System.out.println("success");
}
When I debug this method I see message is null when cursor come to email.send(); But this program work succesfully and send lists to users about 1 month.
If I try another sendMail method just like below, mails succesfully coming to my mailbox;
public void sendMail2() throws Exception {
Email email = new SimpleEmail();
email.setHostName("hostname here");
email.setSmtpPort(587);
email.setAuthentication("mail sender user here","userpasswordhere");
email.setSSLOnConnect(false);
email.setFrom("mail sender address here");
email.setSubject("Example simple mail");
email.setMsg("Example simple mail body;\n");
email.addTo("receiver user here");
email.addTo("receiver user here");
email.send();
System.out.println("success");
}
---Edit---
email.setMsg("Example important List body;\n"+cominglistString); line edited.
And yes, my list is bigger than 0 I am sure.
Any idea?
---Edit 2---
Really i am shocked now!! I continue debugging and mail come to my mailbox this time when i debugging. Because i see cominglistString and email message box populated this time. Mails dont came sometimes. I am stuck :(
Problem Solved. It was a local Firewall problem. Firewall block communication between Application Machine and Mail Server.
Firewall restarted and problem is gone.
Thanks for all answers.

Strange BlackBerry log

I am using the code below , as part of my push notifications implementation:
private static final String BPAS_URL = "http://pushapi.eval.blackberry.com";
private static final String APP_ID = "3582-M4687r9k9k836r980kO2395i32i66y11a34";
String registerUrl = formRegisterRequest(BPAS_URL, APP_ID, null) + ";deviceside=false;ConnectionType=mds-public";
System.out.println("\n\n\n !!msg registerBPAS URL is: "+ registerUrl + "\n\n");
where :
private static String formRegisterRequest(String bpasUrl, String appId, String token) {
StringBuffer sb = new StringBuffer(bpasUrl);
sb.append("/mss/PD_subReg?");
sb.append("serviceid=").append(appId);
sb.append("&osversion=").append(DeviceInfo.getSoftwareVersion());
sb.append("&model=").append(DeviceInfo.getDeviceName());
if (token != null && token.length() > 0) {
sb.append("&").append(token);
}
return sb.toString();
}
What i get printed is this :
!!msg registerBPAS URL is: http://pushapi.eval.blackberry.com/mss/PD_subReg?serviceid=3582-M4687r9[0.0] k9k836r980kO2395i32i66y11a34&osversion=5.0.0.669&model=9520;deviceside=false;ConnectionType=mds-publ[0.0] ic
I cant understand why though. Why there are spaces " " in the URL and why is there a "[0.0]"
From the code above i cant explain this behavior.
What i would expect to be printed is this:
!!msg registerBPAS URL is: http://pushapi.eval.blackberry.com/mss/PD_subReg?serviceid=3582-M4687r9k9k836r980kO2395i32i66y11a34&osversion=5.0.0.669&model=9520;deviceside=false;ConnectionType=mds-public
*I dont have BIS enabled if this is any help , but i dont think it matters as i am forming the URL locally.
All you're seeing is an extra [0.0] in your log in a couple places.
This is normal ... your URL is fine.
Calling
System.out.println("");
does not give you exclusive, or atomic, access to stdout. In other words, while the log is printing out the String you passed to println(), you can also get these tokens printed to the log, and other messages from the BlackBerry OS, and they may/will be placed right in the middle of your log output.
It's annoying, but there's nothing wrong with your code.
If you want another option, look at the BlackBerry EventLogger API, which writes to a log that you can pull off the device, and search through for your messages, without the annoying [0.0].

Categories