Java send email through gmail, sometimes works sometimes hang - spring

I am sending email by Gmail through my web app.
However, sometimes it is working fine but sometimes it just stop without any message.
Does anyone know how to solve this?
In my spring AppConfig.java
#Bean
public JavaMailSender getMailSender(){
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost("smtp.gmail.com");
mailSender.setPort(587);
mailSender.setUsername("my email from");
mailSender.setPassword("my email password");
Properties javaMailProperties = new Properties();
javaMailProperties.put("mail.smtp.starttls.enable", "true");
javaMailProperties.put("mail.smtp.auth", "true");
//javaMailProperties.put("mail.transport.protocol", "smtps");
javaMailProperties.put("mail.transport.protocol", "smtp");
javaMailProperties.put("mail.debug", "true");
mailSender.setJavaMailProperties(javaMailProperties);
return mailSender;
}
In my mailService.java
public void sendEmailWithTemplate(Activity activity, Object object) {
Member member = (Member) object;
MimeMessagePreparator verificationEmail = getEmailFromActivity(activity, member);
try {
mailSender.send(verificationEmail);
System.out.println("Message sent.............................");
} catch (MailException ex) {
System.err.println(ex.getMessage());
}
}
private MimeMessagePreparator getEmailFromActivity(final Activity activity, final Member member) {
MimeMessagePreparator preparator = new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws Exception {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setSubject(activity.getActivity_subject());
helper.setFrom("my from email");
helper.setTo(member.getEmail());
String mailContent = activity.getActivity_content();
helper.setText(mailContent, true);
}
};
return preparator;
}
Sometimes its working fine and I will be able to send the mail, but sometime is just stop for more than 20 minutes at:
DEBUG SMTP: enable SASL
DEBUG SMTP: useEhlo true, useAuth false
DEBUG SMTP: trying to connect to host "smtp.gmail.com", port 587, isSSL false

This is the method I get from other post, but I can't look back the post.
Activity is one of my object storing the subject and content.
public void sendEmailWithActivity(Activity activity, Object object, String path) {
try {
Member member = (Member) object;
String host = "smtp.gmail.com";
String username = "email";
String password = "password";
String body = activity.getActivity_content();
String name = activity.getActivity_name();
String subject = activity.getActivity_subject();=
//Set the properties
Properties props = new Properties();
props.put("mail.smtps.auth", "true");
// Set the session here
Session session = Session.getDefaultInstance(props);
MimeMessage msg = new MimeMessage(session);
// set the message content here
msg.setSubject(subject);
msg.setContent(body, "text/html");
msg.setFrom(new InternetAddress(username));
msg.addRecipient(Message.RecipientType.TO,
new InternetAddress(member.getEmail()));
Transport t = session.getTransport("smtps");
t.connect(host, username, password);
t.sendMessage(msg, msg.getAllRecipients());
t.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}

Related

Schedule emails using Spring boot and Quartz

I would Like to send emails daily using Spring boot, the user specifies the time of sending, I used quartz to schedule my Job. The recipients of emails have(id, emailAddress, deadline) The email will be sent to the people who have deadline = Today + X.. (The user specifies the X). For example: The user specifies that X is number 1, so we're interested in people who have deadline tomorow.
Day1: the app sent emails to people who have deadline = today +1..
Day2: I want that the application send the email at Day2 to new recipients, but with the code below, the email is sent to the same recipients of Day1, and that's not what I need.
#PostMapping("/**")
public ResponseEntity<ScheduleEmailResponse> SendScheduleEmailPeriodic(
#Valid #RequestBody PeriodicNotification scheduleEmailRequest) throws Exception {
ens.schedulePeriodicNotification(scheduleEmailRequest);
LocalDate localDateTime = LocalDate.now();
LocalTime localTime = LocalTime.parse(scheduleEmailRequest.getSendingTime());
try {
ZonedDateTime dateTime = ZonedDateTime.of(localDateTime, localTime,ZoneId.of("**"));
if (dateTime.isBefore(ZonedDateTime.now())) {
ScheduleEmailResponse scheduleEmailResponse = new ScheduleEmailResponse(false,
"dateTime must be after current time");
return ResponseEntity.badRequest().body(scheduleEmailResponse);
}
JobDetail jobDetail = buildPeriodicJobDetail(scheduleEmailRequest);
Trigger trigger = buildJobTriggerPeriodic(jobDetail, dateTime);
scheduler.scheduleJob(jobDetail, trigger);
ScheduleEmailResponse scheduleEmailResponse = new ScheduleEmailResponse(true, jobDetail.getKey().getName(),
jobDetail.getKey().getGroup(), "Email Scheduled Successfully!");
return ResponseEntity.ok(scheduleEmailResponse);
} catch (SchedulerException ex) {
logger.error("Error scheduling email", ex);
ScheduleEmailResponse scheduleEmailResponse = new ScheduleEmailResponse(false,
"Error scheduling email. Please try later!");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(scheduleEmailResponse);
}
}
private JobDetail buildPeriodicJobDetail(PeriodicNotification scheduleEmailRequest) {
JobDataMap jobDataMap = new JobDataMap();
List<String> recipients = fileRepo.findWantedEmails(scheduleEmailRequest.getDaysNum());
if(recipients.isEmpty()) {
throw new RuntimeException("Aucun destinataire trouvé");
}
String[] to = recipients.stream().toArray(String[]::new);
jobDataMap.put("recipients", to);
jobDataMap.put("subject", scheduleEmailRequest.getSubject());
jobDataMap.put("body", scheduleEmailRequest.getMessage());
return JobBuilder.newJob(EmailJob.class).withIdentity(UUID.randomUUID().toString(), "email-jobs")
.withDescription("Send Email Job").usingJobData(jobDataMap).storeDurably().build();
}
private Trigger buildJobTriggerPeriodic(JobDetail jobDetail, ZonedDateTime startAt) {
return TriggerBuilder.newTrigger().forJob(jobDetail)
.withIdentity(jobDetail.getKey().getName(), "email-triggers")
.withDescription("Send Periodic Email Trigger")
.withSchedule(SimpleScheduleBuilder
.repeatHourlyForever(24))
.startAt(Date.from(startAt.toInstant()))
.build();
}
This is the job:
#Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.info("Executing Job with key {}", context.getJobDetail().getKey());
JobDataMap jobDataMap = context.getMergedJobDataMap();
String subject = jobDataMap.getString("subject");
String body = jobDataMap.getString("body");
String[] recipients = (String[])jobDataMap.get("recipients");
sendMail("**", recipients, subject, body);
}
private void sendMail(String fromEmail, String[] toEmail, String subject, String body) {
try {
logger.info("Sending Email to {}", Arrays.toString(toEmail));
MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(message, StandardCharsets.UTF_8.toString());
messageHelper.setSubject(subject);
messageHelper.setText(body, true);
messageHelper.setFrom(fromEmail);
messageHelper.setTo(toEmail);
mailSender.send(message);
} catch (MessagingException ex) {
logger.error("Failed to send email to {}", Arrays.toString(toEmail));
}
}
}

Send emails to multiple email addresses, It feeds email addresses from a csv file

I wanna create an application to send emails to several recipients. It feeds email addresses from a csv file and sends an email to each recipient, and I'm getting some trouble doing this.
Could you help me please?
Here is my CSVHelper.java
#Component
public class CSVHelper
{
public static String TYPE = "text/csv";
static String[] HEADERs = { "id", "email", "dateEcheance"};
//This method is used to filter the csv file and get only the emails
public List<ContactsFile> csvToEmails() throws NumberFormatException, ParseException
{
InputStream is = null;
try (BufferedReader fileReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
CSVParser csvParser = new CSVParser(fileReader, CSVFormat.DEFAULT.withFirstRecordAsHeader().withIgnoreHeaderCase().withTrim());)
{
List<ContactsFile> emailsList = new ArrayList<>();
Iterable<CSVRecord> csvRecords = csvParser.getRecords();
for (CSVRecord csvRecord : csvRecords)
{
ContactsFile contact = new ContactsFile(csvRecord.get("email"));
emailsList.add(contact);
}
System.out.println(emailsList);
return emailsList;
}
catch (IOException e) { throw new RuntimeException("fail to get emails: " + e.getMessage()); }
}
We call csvToEmails() method in the controller to send the emails
#Autowired
private CSVHelper csvHelper;
#PostMapping("/getdetails")
public #ResponseBody EmailNotification sendMail(#RequestBody EmailNotification details) throws Exception {
MimeMessage message = sender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,
MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
StandardCharsets.UTF_8.name());
try {
helper.setTo((InternetAddress) csvHelper.csvToEmails());
helper.setText(details.getMessage(),true);
helper.setSubject("Test Mail");
} catch (javax.mail.MessagingException e) {
e.printStackTrace();
}
sender.send(message);
return details;
this is an example of the csv file:
id,email,dateEcheance
1,address#email.com,10/05/2021
2,address2#email.com,10/02/2021
I'm new to spring boot, and I'm in trouble completing this project.
Assuming that you've mail server configurations in place. First, you need to provide the JavaMailSender implementation. Spring does provide the implementation for the same. You've to create a bean and config the mail server configurations as follows.
#Configuration
public class MailConfig {
#Autowired
private Environment env;
#Bean
public JavaMailSender mailSender() {
try {
JavaMailSenderImpl mailSenderImpl = new JavaMailSenderImpl();
mailSenderImpl.setHost(env.getRequiredProperty("mail.smtp.host"));
mailSenderImpl.setUsername(env.getRequiredProperty("mail.smtp.username"));
mailSenderImpl.setPassword(env.getRequiredProperty("mail.smtp.password"));
mailSenderImpl.setDefaultEncoding(env.getRequiredProperty("mail.smtp.encoding"));
mailSenderImpl.setPort(Integer.parseInt(env.getRequiredProperty("mail.smtp.port")));
mailSenderImpl.setProtocol(env.getRequiredProperty("mail.transport.protocol"));
Properties p = new Properties();
p.setProperty("mail.smtp.starttls.enable", "true");
p.setProperty("mail.smtp.auth", "true");
mailSenderImpl.setJavaMailProperties(p);
return mailSenderImpl;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Configuration settings in application.properties. Add settings according to the mail server.
# SMTP mail settings
mail.smtp.host=**********
mail.smtp.username=**********
mail.smtp.password=**********
mail.smtp.port=**********
mail.smtp.socketFactory.port=**********
mail.smtp.encoding=utf-8
mail.transport.protocol=smtp
mail.smtp.auth=true
mail.smtp.timeout=10000
mail.smtp.starttls.enable=true
mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
CSVHelper.java
#Component
public class CSVHelper {
// This method is used to filter the csv file and get only the emails
public List<String> csvToEmails() {
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("csvFile.csv");
try (BufferedReader fileReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
CSVParser csvParser = new CSVParser(fileReader,
CSVFormat.DEFAULT.withFirstRecordAsHeader().withIgnoreHeaderCase().withTrim());) {
List<String> emails = new ArrayList<>();
Iterable<CSVRecord> csvRecords = csvParser.getRecords();
for (CSVRecord csvRecord : csvRecords) {
String email = csvRecord.get("email");
emails.add(email);
}
return emails;
} catch (IOException e) {
throw new RuntimeException("fail to get emails: " + e.getMessage());
}
}
}
Send mail service
#Service
public class MailSenderService {
#Autowired
private CSVHelper csvHelper;
#Autowired
private JavaMailSender sender;
public void sendMail(EmailNotification details) {
try {
List<String> recipients = csvHelper.csvToEmails();
String[] to = recipients.stream().toArray(String[]::new);
JavaMailSenderImpl jms = (JavaMailSenderImpl) sender;
MimeMessage message = jms.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true);
// add the sender email address below
helper.setFrom("sender#mail.com");
helper.setTo(to);
helper.setText(details.getMessage(), true);
helper.setSubject("Test Mail");
sender.send(message);
} catch (javax.mail.MessagingException | NumberFormatException e) {
// action for exception case
}
}
}

Spring/Java Mail:The sender is always the spring.mail.username. The FROM address is being ignored

I send mail using SimpleMailMessage. Everything is working nicely. But I don't know why on the receiver side shows spring.mail.username's address and not the From Adress.
Each mail sent to the right address but from the address mail which is created in property spring.mail.username
What method will use for this? Is there any method available in SimpleMailMessage Class?
resources/application.properties
spring.mail.host = smtp.gmail.com
spring.mail.port=587
spring.mail.username = ***#otherdomain
spring.mail.password = ***
spring.mail.properties.mail.smtp.auth = true
spring.mail.properties.mail.smtp.starttls.enable=true
Code
private JavaMailSender javaMailSender;
public EmailService(JavaMailSender javaMailSender) {
this.javaMailSender = javaMailSender;
}
public void sendMail(String fromEmail,String toEmail, String subject, String message) {
var mailMessage = new SimpleMailMessage();
mailMessage.setFrom(fromEmail);
mailMessage.setTo(toEmail);
mailMessage.setSubject(subject);
mailMessage.setText(message);
javaMailSender.send(mailMessage);
}
It's not possible to change FROM EMAIL address since it's hard coded: spring.mail.username = ***#otherdomain in resources/application.properties.
But you set the name using MimeMessagePreparator
try {
MimeMessagePreparator preparator = (mimeMessage) -> {
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
helper.setFrom(new InternetAddress("no-reply#gmail.com", "JACK SPARROW"));
helper.setTo("example#gmail.com");
helper.setSubject("Sample email");
helper.setText("Message from ....", true);
};
javaMailSender.send(preparator);
} catch (MailException exception) {
throw exception;
}

how to format tables in Mails / outlook

I am sending email using Spring MVC but It is showing differently In Browser and outlook email
#Service("emailService")
public class EmailService {
#Autowired
private JavaMailSender mailSender;
StringBuilder ResponseTable=new StringBuilder();
public void sendMail(String emailid,String subject,int
tracking_id,String classification_type){
MimeMessage message=mailSender.createMimeMessage();
MimeMessageHelper helper=new MimeMessageHelper(message,true,"UTF- 8");
helper.setTo(emailid);
helper.setText(ResponseTable.toString(),true);
helper.setSubject(subject);
mailSender.send(message);
}
}
You can use a velocity Engine Template to create a custom template :
create your template mailTemplate.vm
create a methode where you can insert you data in a model
create a methode to insert this model in your template
1.mailTemplate.vm
<html>
<head></head>
<body>
<p>hello,</p>
<p>${variable}</p>
</body>
</html>
Create Model to send the Notification Mail
public Boolean NotificationMail(String sender, String receiver, String url,
String subject,String footer) {
LOG.info(" ... Sending new Subscription Notification Mail ");
try {
JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
mailSender.setHost(mailHost);
mailSender.setPort(port);
mailSender.setJavaMailProperties(setMailProperties());
Map<String, Object> model = new HashMap<String, Object>();
model.put("variable", "hello this is the text will be display in the mail");
String body = getVelocityTemplate(model);
LOG.info("Mail host {} , Port {} , url {} , sender {} , receiver {} , subject {} , body {} ",
mailHost, port, url, sender, receiver, subject, body);
Boolean sent = mailService.sendMailWithImg(sender, receiver, subject, body);
return true;
} catch (IllegalArgumentException e) {
LOG.error("IllegalArgumentException , Missing configuration", e);
} catch (Exception e) {
LOG.error("General Exception :{}", e);
}
return false;
}
insert model in the Template
protected String getVelocityTemplateContent(Map<String, Object> model) {
StringWriter stringWriter = new StringWriter();
StringBuilder builder = new StringBuilder();
builder.append("/template/mailTemplate.vm");
try {
VelocityEngineUtils.mergeTemplate(velocityEngine, builder.toString(), "UTF8", model,
stringWriter);
return stringWriter.toString();
} catch (Exception e) {
LOG.error("Error",e);
}
return null;
}
}

Why do I get an IOException in sending an email with Gmail service?

In my android test application, after that i got the JSON file from the Google Developer Console, where i had set on the Gmail API, and that i have put it in the emulator, i get an IOException which says:
"com.google.api.client.googleapis.json.GoogleJsonResponseException:
403 Forbidden { "code" : 403, "errors" : [ {
"domain" : "usageLimits",
"message" : "Access Not Configured. Please use Google Developers Console to activate the API for your project.",
"reason" : "accessNotConfigured" } ], "message" : "Access Not Configured. Please use Google Developers Console to activate the API
for your project." }"
I think that I must use a GoogleClientSecrets object, but i haven't found its use.
Here the code:
public class MainActivity extends Activity
{
final String SCOPE = "oauth2:https://www.googleapis.com/auth/gmail.compose";
final String FILE_NAME = "TestEmail5.json";
private static final int REQUEST_RESOLVE_ERROR = 1001;
Button button;
OnClickListener sendListener = new OnClickListener()
{
#Override
public void onClick(View v)
{
new sendEmailTask().execute();
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button)findViewById(R.id.button1);
button.setOnClickListener(sendListener);
}
public static MimeMessage createEmail(String to, String from, String subject, String bodyText) throws MessagingException
{
Properties props = new Properties();
Session session = Session.getDefaultInstance(props, null);
MimeMessage email = new MimeMessage(session);
InternetAddress tAddress = new InternetAddress(to);
InternetAddress fAddress = new InternetAddress(from);
email.setFrom(new InternetAddress(from));
email.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to));
email.setSubject(subject);
email.setText(bodyText);
return email;
}
public static void sendMessage(Gmail service, String userId, MimeMessage email) throws MessagingException, IOException
{
Message message = createMessageWithEmail(email);
message = service.users().messages().send(userId, message).execute();
System.out.println("Message id: " + message.getId());
System.out.println(message.toPrettyString());
}
public static Message createMessageWithEmail(MimeMessage email) throws MessagingException, IOException
{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
email.writeTo(bytes);
String encodedEmail = Base64.encodeBase64URLSafeString(bytes.toByteArray());
Message message = new Message();
message.setRaw(encodedEmail);
return message;
}
public class sendEmailTask extends AsyncTask
{
#Override
protected Object doInBackground(Object... params)
{
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = new JacksonFactory();
String token = "";
AccountManager accountManager = AccountManager.get(MainActivity.this);
Account account[] = accountManager.getAccountsByType("com.google");
String accountName = account[0].name;
try
{
//GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(jsonFactory, new java.io.FileReader(Environment.getExternalStorageDirectory().getAbsolutePath() + "//" + "JSON/" + FILE_NAME));
token = GoogleAuthUtil.getToken(MainActivity.this, accountName, SCOPE);
GoogleCredential credential = new GoogleCredential().setAccessToken(token);
Gmail service = new Gmail.Builder(httpTransport, jsonFactory, credential).setApplicationName("TestEmail5").build();
MimeMessage mm = createEmail("myemail", "myemail", "soggetto", "oggetto");
sendMessage(service, "myemail", mm);
}
catch (UserRecoverableAuthException e)
{
startActivityForResult(e.getIntent(), REQUEST_RESOLVE_ERROR);
}
catch (IOException e)
{
e.printStackTrace();
}
catch (GoogleAuthException e)
{
e.printStackTrace();
}
catch (MessagingException e)
{
e.printStackTrace();
}
return null;
}
};
}
You need to login to http://console.developers.google.com/ and create a project and activate the "Gmail" API for it.
Documented more at:
https://developers.google.com/gmail/api/quickstart/quickstart-java#step_1_enable_the_gmail_api

Resources