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

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
}
}
}

Related

Loading value from json upon start up application

I want to load the values from json file upon the Spring Boot Application is started.
My code for the Configuration File is like the below:
#Configuration
#Getter
public class FedexAPIConfig {
private final static String JSON_FILE = "/static/config/fedex-api-credentials.json";
private final boolean IS_PRODUCTION = false;
private FedexAPICred apiCredentials;
public FedexAPIConfig() {
try (InputStream in = getClass().getResourceAsStream(JSON_FILE);
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
JSONObject json = new JSONObject();
// this.apiCredentials = new JSONObject(new JSONTokener(reader));
if (IS_PRODUCTION) {
json = new JSONObject(new JSONTokener(reader)).getJSONObject("production");
} else {
json = new JSONObject(new JSONTokener(reader)).getJSONObject("test");
}
System.out.println(json.toString());
this.apiCredentials = FedexAPICred.builder()
.url(json.optString("url"))
.apiKey(json.optString("api_key"))
.secretKey(json.optString("secret_key"))
.build();
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
and with this, when the application is in progress of startup, values are successfully printed on the console.Startup console log
When I tried to call this value from other ordinary class, like the below:, it brings nothing but just throws NullPointerException... What are my faults and what shall I do?
public class FedexOAuthTokenManager extends OAuthToken {
private static final String VALIDATE_TOKEN_URL = "/oauth/token";
private static final String GRANT_TYPE_CLIENT = "client_credentials";
private static final String GRANT_TYPE_CSP = "csp_credentials";
#Autowired
private FedexAPIConfig fedexApiConfig;
#Autowired
private Token token;
#Override
public void validateToken() {
// This is the part where "fedexApiConfig" is null.
FedexAPICred fedexApiCred = fedexApiConfig.getApiCredentials();
Response response = null;
try {
RequestBody body = new FormBody.Builder()
.add("grant_type", GRANT_TYPE_CLIENT)
.add("client_id", fedexApiCred.getApiKey())
.add("client_secret", fedexApiCred.getSecretKey())
.build();
response = new HttpClient().post(fedexApiCred.getUrl() + VALIDATE_TOKEN_URL, body);
if (response.code() == 200) {
JSONObject json = new JSONObject(response.body().string());
token.setAccessToken(json.optString("access_token"));
token.setTokenType(json.optString("token_type"));
token.setExpiredIn(json.optInt("expires_in"));
token.setExpiredDateTime(LocalDateTime.now().plusSeconds(json.optInt("expires_in")));
token.setScope(json.optString("scope"));
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
fedexApiConfg is null even though I autowired it in prior to call.
And this FedexOAuthTokenManager is called from other #Component class by new FedexOAuthTokenManager()
Did you try like below?
Step 1: Create one Configuration class like below
public class DemoConfig implements ApplicationListener<ApplicationPreparedEvent> {
#Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
//Load the values from the JSON file and populate the application
//properties dynamically
ConfigurableEnvironment environment = event.getApplicationContext().getEnvironment();
Properties props = new Properties();
props.put("spring.datasource.url", "<my value>");
//Add more properties
environment.getPropertySources().addFirst(new PropertiesPropertySource("myProps", props));
}
To listen to a context event, a bean should implement the ApplicationListener interface which has just one method onApplicationEvent().The ApplicationPreparedEvent is invoked very early in the lifecycle of the application
Step 2: Customize in src/main/resources/META-INF/spring.factories
org.springframework.context.ApplicationListener=com.example.demo.DemoConfig
Step 3: #Value in spring boot is commonly used to inject the configuration values into the spring boot application. Access the properties as per your wish.
#Value("${spring.datasource.url}")
private String valueFromJSon;
Try this sample first in your local machine and then modify your changes accordingly.
Refer - https://www.baeldung.com/spring-value-annotation
Refer - https://www.knowledgefactory.net/2021/02/aws-secret-manager-service-as.html

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 can't I send CSS decorated html email via spring?

I have successfully sent text email and the bellow implementation sends really basic html emails - I don't get the CSS classes in any of it.
The relevant parts of my MailServiceImpl class are:
protected void prepareAndSendMail(Map<String, String> emailMap) {
try {
InternetAddress[] parsed;
try {
parsed = InternetAddress.parse(emailMap.get("to"));
} catch (AddressException e) {
throw new IllegalArgumentException("Not valid email: " + emailMap.get("to)"), e);
}
MimeMessage mailMessage = javaMailSender.createMimeMessage();
mailMessage.setSubject(emailMap.get("subject"), "UTF-8");
MimeMessageHelper helper = new MimeMessageHelper(mailMessage, true, "UTF-8");
helper.setFrom(emailMap.get("from"));
helper.setTo(parsed);
helper.setText(mailContentBuilderService.buildHTMLTemplate(emailMap.get("text")), true);
javaMailSender.send(mailMessage);
} catch (MessagingException ex) {
throw new RuntimeException(ex);
}
}
protected String buildConfirmRegistrationButton(String label, String confirmationUrl) {
StringBuilder content = new StringBuilder();
content.append("<div class=\"jumbotron\">");
content.append("<div class=\"container-fluid\">");
content.append("<div class=\"form-group row justify-content-md-center justify-content-lg-center justify-content-xl-center\">");
content.append("<label>" + label + "</label> \r\n");
content.append("<br />");
content.append("<a href=\"" + confirmationUrl + "\">");
content.append("<button class=\"btn btn-primary\"> Click here to confirm </button>");
content.append("</a>");
content.append("</div>");
content.append("</div>");
content.append("</div>");
return content.toString();
}
#Override
public void sendNewUserRegistrationToken_HTML(OnRegistrationCompleteEvent onRegistrationCompleteEvent, User user, String token) {
Locale locale = Locale.US;
final String subject = messageSource.getMessage("mail.registrationConfirmationSubject", null, locale);
final String label = messageSource.getMessage("mail.registrationConfirmationLabel", new Object[]{user.getEmail()}, locale);
final String confirmationUrl = onRegistrationCompleteEvent.getAppUrl() + "/admin/user/registration/confirm?token=" + token;
final String content = buildConfirmRegistrationButton(label, confirmationUrl);
Map<String, String> emailMap = new HashMap<>();
emailMap.put("to", user.getEmail());
emailMap.put("from", environment.getProperty("support.email"));
emailMap.put("subject", subject);
emailMap.put("text", content);
prepareAndSendMail(emailMap);
}
The prepareAndSendMail method calls mailContentBuilderService.buildHTMLTemplate(String text) and is defined as:
private TemplateEngine templateEngine;
#Autowired
public MailContentBuilderServiceImpl(TemplateEngine templateEngine) {
this.templateEngine = templateEngine;
}
#Override
public String buildHTMLTemplate(String message) {
StringBuilder html = new StringBuilder();
html.append("<!DOCTYPE html>");
html.append("<html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:th=\"http://www.thymeleaf.org\"> ");
html.append("<head>");
html.append("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">");
html.append("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\" integrity=\"sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T\" crossorigin=\"anonymous\">");
html.append("<script src=\"https://code.jquery.com/jquery-3.3.1.slim.min.js\" integrity=\"sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo\" crossorigin=\"anonymous\"></script>");
html.append("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js\" integrity=\"sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1\" crossorigin=\"anonymous\"></script>");
html.append("<script src=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js\" integrity=\"sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM\" crossorigin=\"anonymous\"></script>");
html.append("</head>");
html.append("<body>");
html.append("<div class=\"container\">");
html.append("<div class=\"text-center\">");
html.append(message);
html.append("</div>");
html.append("</div>");
html.append("</body>");
html.append("</html>");
return html.toString();
}
The result I get when I try to register a new user is:
How can I make it look nice, obeying the CSS it should inherit from the CDN?
I have tried using a build method as described below (pointing to the right template, obviously), still no joy.
public String build(String message) {
Context context = new Context();
context.setVariable("message", message);
return templateEngine.process("mailTemplate", context);
}
You need to understand that email does not conform to normal web standards. You cannot add scripts to email. You cannot add external stylesheets (most will get stripped; see also this answer: Can you link to a CSS file from an email?).
You must embed CSS in the <head>, i.e.:
html.append('<style type="text/css">.container {...}</style>');

Java send email through gmail, sometimes works sometimes hang

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 {
}
}

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