I'm implementing a mail Sender, near 1'6000.000 mails (with images and PDF) in one day per month (closing month extract), the mails are about 12 products...
I need to fill a Message Scratch per product... in order to not read (per email) else per product.
I'm trying to implement cloning javax.mail.Message and javax.mail.Multipart in order to be faster.
AddContent to Multipart
public static void addContent(final Multipart multipart, String contenidoCorreo) throws Exception {
MimeBodyPart mimeBodyPart = new PreencodedMimeBodyPart("8bit");
mimeBodyPart.setText(contenidoCorreo, "iso-8859-1", "html");
multipart.addBodyPart(mimeBodyPart, 0);
}
Add Image per Bytes
public static void addImageToMultipart(final Multipart multipart, byte[] contenidoImagen, String nombreImagen) throws Exception {
MimeBodyPart imagenMimeBodyPart = new MimeBodyPart();
try {
ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource(contenidoImagen, "image/*");
imagenMimeBodyPart.setDataHandler(new DataHandler(byteArrayDataSource));
imagenMimeBodyPart.setFileName(nombreImagen);
imagenMimeBodyPart.setContentID("<" + nombreImagen + ">");
imagenMimeBodyPart.setDisposition(MimeBodyPart.INLINE);
multipart.addBodyPart(imagenMimeBodyPart);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
}
AddPDF per File
public static void addPDF(final Multipart multipart, String ruta, String nombre) throws Exception {
Path path = Paths.get(ruta, nombre);
if (path.toFile().exists()) {
MimeBodyPart preencodedMimeBodyPart = new PreencodedMimeBodyPart("base64");
preencodedMimeBodyPart.attachFile(path.toFile());
preencodedMimeBodyPart.setFileName(nombre);
preencodedMimeBodyPart.setHeader("Content-Type", "application/pdf");
preencodedMimeBodyPart.setDisposition(MimeBodyPart.ATTACHMENT);
multipart.addBodyPart(preencodedMimeBodyPart);
MimeBodyPart pdfMimeBodyPart = new MimeBodyPart();
}
My Cloning Message
public static Message cloneMessage(Message source) {
//Multiple and Separated Exceptions because maybe not all properties are defined in some time.
Message target = new MimeMessage(source.getSession());
try {
if (source.getFrom() != null && source.getFrom().length > 0) {
Address address = (source.getFrom()[0]);
target.setFrom(new InternetAddress(((InternetAddress) address).getAddress(), ((InternetAddress) address).getPersonal()));
}
} catch (Exception ex) {
//Handle Exception
}
try {
target.setSentDate((Date) (source.getSentDate().clone()));
} catch (MessagingException ex) {
//Handle Exception
}
try {
target.setRecipients(Message.RecipientType.TO, target.getRecipients(Message.RecipientType.TO).clone());
} catch (MessagingException ex) {
//Handle Exception
}
try {
Enumeration numerationHeaders = source.getAllHeaders();
while (numerationHeaders.hasMoreElements()) {
Header header = (Header) numerationHeaders.nextElement();
target.addHeader(header.getName(), header.getValue());
}
} catch (MessagingException ex) {
//Handle Exception
}
try {
target.setSubject(new String(source.getSubject()));
} catch (MessagingException ex) {
//Handle Exception
}
try {
target.setContent(cloneMultipart((Multipart)(source.getContent())));
} catch (Exception ex) {
//Handle Exception
}
return target;
}
Cloning Multipart
public static Multipart cloneMultipart(Multipart source) {
MimeMultipart target = new MimeMultipart();
try {
for (int i = 0; i < source.getCount(); i++) {
MimeBodyPart mimeBodyPart = (MimeBodyPart)source.getBodyPart(i);
mimeBodyPart //?????
}
} catch (MessagingException ex) {
//Handle Exception
}
return target;
}
How cloning Multipart?
some advice to clone Message?
How detect the Content (the used with addContent method) has been added?
Related
We have a spring boot Application which makes RESTFul calls to a bunch of backends, one of them returns null reponses at times, and we are observing the connections are not released during these instances because of this code in RestTemplate class:
protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,
ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "'url' must not be null");
Assert.notNull(method, "'method' must not be null");
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
if (responseExtractor != null) {
return responseExtractor.extractData(response);
}
else {
return null;
}
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
}
Is there a way we can release the connection or consume the contents for when response is null or erring out?
Edited to add code causing errors:
MyHttpClientClass{
private X getResponseBody(RestClient client, URI uri, HttpMethod method, HttpEntity<T> entity, Class<R> responseType, MyErrorHandler errorHandler) {
try
{ String host = this.getHost();
ResponseEntity<X> resp = client.exchange(uri, method, entity, responseType);
return resp.getBody();
} catch (HttpServerErrorException | HttpClientErrorException e)
{ handleHttpException(e, errorHandler);
throw e;
} catch (Exception e) {
log(e);
throw e; } } }
-----------
Class1 implements Callable<T>
{
#Override public T doCall() throws Exception {
try
{ return this.getRestClient().exchange(this.getUri(),
this.getHttpMethod(), this.getEntity(), getResponseType()).getBody(); } catch (HttpClientErrorException ex) { throw ex; } catch (HttpStatusCodeException ex) { if(this.isNeededRetry(ex)) { throw ex; }else { return generateErrorResponse(ex).getBody(); } } catch (RestClientException ex) { throw ex; } catch (Exception ex) { throw ex; } } }
----------
MySpringApplicationClass{
public X get(String api, String params, Class<R> responseType, String path, List<String> pathVariables, MyErrorHandler errorHandler)
{
return getResponseBody(...);
}}
I have this below code for downloading CSV as an ajax button click, But the file is not downloading. Only showing the black new tab on the browser.
#RequestMapping(value = "/batch/download", method = RequestMethod.POST, produces = "text/csv")
#ResponseBody
public void downloadNGIBatchSelected(HttpServletResponse response) throws IOException {
List<String> ids = Arrays.asList("1312321","312313");
generateNewCustomerCSV(response.getWriter(),ids);
}
private void generateNewCustomerCSV(PrintWriter writer, List<String> ids){
String NEW_LINE_SEPARATOR = "\n";
//CSV file header
Object[] FILE_HEADER = {"Token Number",
"Token Expiry Date",
};
CSVPrinter csvPrinter = null;
try {
csvPrinter = new CSVPrinter(new BufferedWriter(writer), CSVFormat.DEFAULT.withRecordSeparator(NEW_LINE_SEPARATOR));
//Create CSV file header
csvPrinter.printRecord(FILE_HEADER);
for (PolicyMap PolicyMap : policyMaps) {
List customerCSV = new ArrayList();
customerCSV.add(PolicyMap.getInsurancePolicy().getTokenNo());
try {
csvPrinter.printRecord(customerCSV);
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
writer.flush();
writer.close();
csvPrinter.close();
} catch (IOException e) {
System.out.println("Error while flushing/closing fileWriter/csvPrinter !!!");
e.printStackTrace();
}
}
}
You have set the content type in #RequestMapping annotation. But it is not going to work in the case when response is being written using HttpServletResponse. In this case, instead of spring, HttpServletResponse is writing the response that's why you have to set the response type in the response before getting the writer.
response.setContentType ("application/csv");
response.setHeader ("Content-Disposition", "attachment; filename=\"nishith.csv\"");
I am trying to save data in authData field android, But I am getting exception: Cannot save a ParseUser that is not authenticated" after only reading the user
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereEqualTo("username", email);
query.findInBackground(new FindCallback<ParseUser>() {
#SuppressWarnings("deprecation")
public void done(List<ParseUser> scoreList, ParseException e) {
if (e == null) {
if(scoreList.size()>0){
facebook_user = (ParseUser) scoreList.get(0);
facebook_user.isAuthenticated()
JSONObject obj = new JSONObject();
try {
obj.put("name", "xyz");
} catch (JSONException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
facebook_user.put("authdata", obj);
facebook_user.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
// exception in this section //
//Cannot save a ParseUser that is not authenticated" after only reading the user//
});
}else{
}
} else {
Log.d("score", "Error: " + e.getMessage());
}
}
});
It looks like you are attempting to modify that user with the .put() before saving:
facebook_user.put("authdata", obj);
facebook_user.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
// exception in this section //
});
If you want to change a user, you need to be logged in as the user, execute the change on Cloud Code using the masterKey, or change the user objects' ACL. Here's a SO post with a bit more info.
Let me know if you have any more questions.
I want to send two kinds email, and some logic could shared. e.g.
try {
MimeMessage msg = javaMailService.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(msg, true, DEFAULT_ENCODING);
//custom code here ...
} catch (MessagingException e) {
logger.error("build email fail", e);
} catch (Exception e) {
logger.error("send email fail", e);
}
above is common code (e.g. sendEmail(Function customCode)), below is custom code of sending email to foo
logger.info("send count mail to {}", toFoo);
helper.setFrom(sender);
helper.setTo(toFoo);
helper.setSubject("Foo Subject");
String content = generateFooContent(foo); //use fooTemplate.ftl
helper.setText(content, true);
javaMailService.send(msg);
I want to this effect,
Function fooFunc = ()->{logger.info("send count mail to {}", toFoo);
helper.setFrom(sender);
helper.setTo(toFoo);
helper.setSubject("Foo");
String content = generateFooContent(foo);
helper.setText(content, true);
javaMailService.send(msg);}
then call sendEmail method,
sendEmail(fooFunc);
If I want to send bar message,
Function barFunc = ()->{...} //cunstom code here
sendEmail(barFunc);
In java8 could achieve this? if could how?
Your "Function" has a signature:
void doStuff(MimeMessageHelper helper)
We already have one of these - it's called a Consumer<MimeMessageHelper>.
So:
final Consumer<MimeMessageHelper> messageCreator = ...
try {
MimeMessage msg = javaMailService.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(msg, true, DEFAULT_ENCODING);
messageCreator.accept(helper);
javaMailService.send(msg);
} catch (MessagingException e) {
logger.error("build email fail", e);
} catch (Exception e) {
logger.error("send email fail", e);
}
Now, to define your sender simply use:
BiConsumer<MimeMessageHelper> fooFunc = helper -> {
logger.info("send count mail to {}", toFoo);
helper.setFrom(sender);
helper.setTo(toFoo);
helper.setSubject("Foo");
String content = generateFooContent(foo);
helper.setText(content, true);
}
P.S. please note my formatting.
Thanks #Boris the Spider, it do works, see below
private void sendFooHtmlMessage(List<Foo> body) {
BiConsumer<MimeMessage,MimeMessageHelper> fooFunc = (msg,helper) -> {
logger.info("send foo mail to {}", toFoo);
try {
helper.setTo(toFoo);
helper.setSubject("Foo Subject");
String content = generateFooContent(body);
helper.setText(content, true);
javaMailService.send(msg);
} catch (Exception e) {
}
};
sendMessage(fooFunc);
}
private void sendMessage(BiConsumer<MimeMessage,MimeMessageHelper> consumer) {
try {
final MimeMessage msg = javaMailService.createMimeMessage();
final MimeMessageHelper helper = new MimeMessageHelper(msg, true, DEFAULT_ENCODING);
helper.setFrom(sender);
consumer.accept(msg, helper);
} catch (MessagingException e) {
logger.error("build email failed", e);
} catch (Exception e) {
logger.error("send email failed", e);
}
}
but still lack something, see above code I have to catch exception in fooFunc, actually I want to throw it because in common sendMesage will catch these exception.
So I adopt another way, see below
public interface SendMessageAction {
void action(MimeMessage msg, MimeMessageHelper helper) throws MessagingException;
}
private void sendMessage(SendMessageAction action) {
//...
}
private void sendFooHtmlMessage(List<Foo> body) {
SendMessageAction fooAction = (msg, helper) -> {
logger.info("send foo mail to {}", toFoo);
//...
};
sendMessage(fooAction);
}
I keep getting a HTML 404 reply from the server when I try to login via a httppost (https). Not sure if this is a cookie problem or something else. The code should be good as I have copied it from another activity. I need some help.
This is my current code:
public int postData(String usernamne, String password) {
String url = "https://domainname.com/nclogin.submit";
HttpPost httppost = new HttpPost(url);
try {
KeyStore trusted = null;
try {
trusted = KeyStore.getInstance("BKS");
} catch (KeyStoreException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
trusted.load(null, "".toCharArray());
MySSLSocketFactory sslf = null;
try {
sslf = new MySSLSocketFactory(trusted);
} catch (KeyManagementException e) {
Log.d(TAG, "Exception " + e);
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
Log.d(TAG, "Exception " + e);
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
Log.d(TAG, "Exception " + e);
// TODO Auto-generated catch block
e.printStackTrace();
}
sslf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("f_username", "myemail#address.com"));
nameValuePairs.add(new BasicNameValuePair("f_passwd", "mypassword"));
nameValuePairs.add(new BasicNameValuePair("f_method", "LOGIN"));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("https", sslf, 443));
SingleClientConnManager cm = new SingleClientConnManager(httppost.getParams(), schemeRegistry);
// NEW API WONT ALLOW THIS IN THE MAIN THREAD! hence ASYNC
DefaultHttpClient client = new DefaultHttpClient(cm, httppost.getParams());
HttpResponse result = client.execute(httppost);
// Check if server response is valid
StatusLine status = result.getStatusLine();
Log.d(TAG, "STatus" + result.getStatusLine());
if (status.getStatusCode() != 200) {
throw new IOException("Invalid response from server: " + status.toString());
}
HttpEntity entity = result.getEntity();
InputStream is = entity.getContent();
if (is != null) {
is.close(); // release connection
}
String phpsessid = "";
// cookies from another blog
// http://stackoverflow.com/questions/4224913/android-session-management
List cookies = client.getCookieStore().getCookies();
if (cookies.isEmpty()) {
Log.d(TAG, "no cookies received");
} else {
for (int i = 0; i < cookies.size(); i++) {
// Log.d(TAG, "COOKIE-" + i + " " +
// cookies.get(i).toString());
if (cookies.get(i).toString().contains("PHPSESSID")) {
phpsessid = cookies.get(i).toString();
Log.d(TAG, "COOKIE FOR PHPSESSID - " + phpsessid);
}
}
} // end of blog
entity.consumeContent();
client.getConnectionManager().shutdown();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
} catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (CertificateException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return 1;
} // end of postData()
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
#Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host,
port, autoClose);
}
#Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
I know the url is correct, as are the name value pairs, as I can login via a query string via a browser or via wget:
https://domainname.com/nclogin.submit?f_username=myemail#email.com&f_passwd=password&f_method=LOGIN
This results in a connection established and a redirect to my dashboard page.
The HTML code (source) from the login page can be viewed
here