Spring Framework, get incoming emails with attachments using IMAP - spring

Using this link, I could not figure out how to get incoming emails with attachments. For example, the mail foo#bar.com receives a letter to which the baz.csv file is attached. How to read the contents of a file?Thank you.

Using java mail platform, you can get attachments of an email:
Multipart multipart = (Multipart) message.getContent();
List<byte[]> attachments = new ArrayList<>();
for (int i = 0; i < multipart.getCount(); i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition()) && bodyPart.getFileName()!=null) {
InputStream is = bodyPart.getInputStream();
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buf = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buf)) != -1) {
os.write(buf, 0, bytesRead);
}
os.close();
attachments.add(os.toByteArray());
}
}
message is an object of type javax.mail.Message.
Now, you have a list of byte[] that each one is one of your mail attachment. You can convert byte[] to File easily.

Related

MQHeaderList size is 0, but reading a specific MQRFH2 works

I am wring custom java code to read messages from Websphere MQ (version 8) and read all the headers from the MQ message.
When I use the MQHeaderList to parse all the headers the list size is 0:
MQMessage message = new MQMessage();
queue.get(message, getOptions);
DataInput in = new DataInputStream (new ByteArrayInputStream (b));
MQHeaderList headersfoundlist = null;
headersfoundlist = new MQHeaderList (in);
System.out.println("headersfoundlist size: " + headersfoundlist.size());
However, I read only a specific MQRFH2 it works
MQMessage message = new MQMessage();
queue.get(message, getOptions);
DataInput in = new DataInputStream (new ByteArrayInputStream (b));
MQRFH2 rfh2 = new MQRFH2(in);
Element usrfolder = rfh2.getFolder("usr", false);
System.out.println("usr folder" + usrfolder);
How can I parse all the headers of the MQ Message?
DataInput in = new DataInputStream (new ByteArrayInputStream (b));
What's that about? Not sure why you want to do that.
It should just be:
MQMessage message = new MQMessage();
queue.get(message, getOptions);
MQHeaderList headersfoundlist = new MQHeaderList(message);
System.out.println("headersfoundlist size: " + headersfoundlist.size());
Read more here.
Update:
#anshu's comment about it not working, well, I've always found MQHeaderList class to be very buggy. Hence, that is why I don't use it.
Also, 99.99% messages in MQ will only ever have 1 embedded MQ header (i.e. MQRFH2). Note: A JMS message == MQRFH2 message. The only case where you will find 2 embedded MQ headers are for messages on the Dead Letter Queue.
i.e.
{MQDLH}{MQRFH2}{message payload}
Is there a real need for your application to process multiple embedded MQ headers? Is your application putting/getting JMS messages (aka MQRFH2 messages)?
If so then you should do something like the following:
queue.get(receiveMsg, gmo);
if (CMQC.MQFMT_RF_HEADER_2.equals(receiveMsg.format))
{
receiveMsg.seek(0);
MQRFH2 rfh2 = new MQRFH2(receiveMsg);
int strucLen = rfh2.getStrucLength();
int encoding = rfh2.getEncoding();
int CCSID = rfh2.getCodedCharSetId();
String format= rfh2.getFormat();
int flags = rfh2.getFlags();
int nameValueCCSID = rfh2.getNameValueCCSID();
String[] folderStrings = rfh2.getFolderStrings();
for (String folder : folderStrings)
System.out.println.logger("Folder: "+folder);
if (CMQC.MQFMT_STRING.equals(format))
{
String msgStr = receiveMsg.readStringOfByteLength(receiveMsg.getDataLength());
System.out.println.logger("Data: "+msgStr);
}
else if (CMQC.MQFMT_NONE.equals(format))
{
byte[] b = new byte[receiveMsg.getDataLength()];
receiveMsg.readFully(b);
System.out.println.logger("Data: "+new String(b));
}
}
else if ( (CMQC.MQFMT_STRING.equals(receiveMsg.format)) ||
(CMQC.MQFMT_NONE.equals(receiveMsg.format)) )
{
Enumeration<String> props = receiveMsg.getPropertyNames("%");
if (props != null)
{
System.out.println.logger("Named Properties:");
while (props.hasMoreElements())
{
String propName = props.nextElement();
Object o = receiveMsg.getObjectProperty(propName);
System.out.println.logger(" Name="+propName+" : Value="+o);
}
}
if (CMQC.MQFMT_STRING.equals(receiveMsg.format))
{
String msgStr = receiveMsg.readStringOfByteLength(receiveMsg.getMessageLength());
System.out.println.logger("Data: "+msgStr);
}
else
{
byte[] b = new byte[receiveMsg.getMessageLength()];
receiveMsg.readFully(b);
System.out.println.logger("Data: "+new String(b));
}
}
else
{
byte[] b = new byte[receiveMsg.getMessageLength()];
receiveMsg.readFully(b);
System.out.println.logger("Data: "+new String(b));
}
I found the mistake in my code. I have a few more steps before reading the headers. It was moving the cursor in message buffer to the end.
I added message.setDataOffset(0); before reading headers and it worked.

How to get File in Content-Disposition attachment using WebRequest and/or HTML Agility Pack

I'm developting a web crawler that will download a PDF file from a website.
I checked the source code of the website before and I discovery that the button which download the PDF is actually a submit input to a form. That form retrives the file in Content-Disposition header in response.
Here's a picture of it:
My question is, how to get this file using web request (or HTML Agility pack). I tried in this way, but the hearder returns null.
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
string file = response.Headers["Content-Disposition"];
Thanks in advance
I already have my answers, here is what I've done to get the file
response = (HttpWebResponse)request.GetResponse();
stream = response.GetResponseStream();
byte[] retorno = ReadToEnd(stream);
response.Close();
stream.Close();
public static byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = 0;
if (stream.CanSeek)
{
originalPosition = stream.Position;
stream.Position = 0;
}
try
{
byte[] readBuffer = new byte[4096];
int totalBytesRead = 0;
int bytesRead;
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;
if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}
byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
if (stream.CanSeek)
{
stream.Position = originalPosition;
}
}
}
thanks

Upload large files to Azure Media Services in Xamarin

I am trying to upload a .mp4 file, selected from the user's iOS or Android device, to my Azure Media Services account.
This code works for small files ( less than ~95MB):
public static async Task<string> UploadBlob(string blobContainerSasUri, string blobName, byte[] blobContent, string path)
{
string responseString;
int contentLength = blobContent.Length;
string queryString = (new Uri(blobContainerSasUri)).Query;
string blobContainerUri = blobContainerSasUri.Split('?')[0];
string requestUri = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}/{1}{2}", blobContainerUri, blobName, queryString);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
request.Method = "PUT";
request.AllowWriteStreamBuffering = false;
request.Headers.Add("x-ms-blob-type", "BlockBlob");
request.ContentLength = contentLength;
request.Timeout = Int32.MaxValue;
request.KeepAlive = true;
int bufferLength = 1048576; //upload 1MB at time, useful for a simple progress bar.
Stream requestStream = request.GetRequestStream();
requestStream.WriteTimeout = Int32.MaxValue;
ProgressViewModel progressViewModel = App.Locator.GetProgressBar(App.Locator.MainViewModel.currentModuleItemId);
MyVideosPage myVideosPage = App.Locator.GetVideosPage(App.Locator.MainViewModel.currentModuleItemId);
FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
int nRead = 0;
int currentPos = 0;
while ((nRead = fileStream.Read(blobContent, currentPos, bufferLength)) > 0)
{
await requestStream.WriteAsync(blobContent, currentPos, nRead);
currentPos += nRead;
}
fileStream.Close();
requestStream.Close();
HttpWebResponse objHttpWebResponse = null;
try
{
// this is where it fails for large files
objHttpWebResponse = (HttpWebResponse)request.GetResponse();
Stream responseStream = objHttpWebResponse.GetResponseStream();
StreamReader stream = new StreamReader(responseStream);
responseString = stream.ReadToEnd();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (objHttpWebResponse != null)
objHttpWebResponse.Close();
}
return responseString;
}
An exception is thrown after this line is called:
(HttpWebResponse)request.GetResponse();
The exception message is "The request body is too large and exceeds the maximum permissible limit."
The exception StatusCode is "RequestEntityTooLarge".
How can I upload large files? Is this a problem with HttpWebRequest, or Azure Media Services?
Azure Storage supports one shot upload (aka PutBlob API) up to 256MB if you are using the new REST API versions. But since you are not specifying the REST API version, you're defaulting to a very old version where the maximum supported size of one shot upload is 100MB.
Use x-ms-version: 2018-03-28 header to be able to upload up to 256MB in one HTTP request.
If you have to deal with larger files, you will need to use block & commit upload. You will need to use PutBlock API to stage blocks from the source file. Blocks can be up to 100MB each. Then you need to commit all the blocks using the PutBlockList API. If you don't have to deal with this logic yourself, simply use the Azure Storage SDK for .NET (supports Xamarin) and use the uploadFromFile method. It is simple, and resilient.

Saving base64String as image on FTP server, saves corrupted file

Saving base64String as image on FTP Server is saving it as corrupted file.
I am doing following things
converted base64String into byte[].
Initialized MemoryStream with byte converted in above step.
Opened stream from FTP
Write stream on ftp.
Below is the code
public bool WriteFromBase64ToFile(string base64, string path, string fileName)
{
bool result = false;
using (FtpClient ftp = new FtpClient())
{
// setting ftp properties with required values.
ftp.ReadTimeout = 999999999;
ftp.Host = host;
ftp.Credentials = new System.Net.NetworkCredential(username, password);
ftp.Port = Convert.ToInt32(port);
ftp.DataConnectionType = FtpDataConnectionType.AutoPassive;
ftp.Connect();
ftp.ConnectTimeout = 1000000;
// converting base64String into byte array.
byte[] file = Convert.FromBase64String(base64);
if (ftp.IsConnected)
{
int BUFFER_SIZE = file.Length; // 64KB buffer
byte[] buffer = new byte[file.Length];
// Initializing MemoryStream with byte converted from base64String.
MemoryStream ms = new MemoryStream(buffer);
using (Stream readStream = ms)
{
fileName = fileName.ReplacingSpecialCharacterswithEntities();
// Getting stream from ftp and then writing it on FTP server.
using (Stream writeStream = ftp.OpenWrite(path + "/" + fileName+".jpg", FtpDataType.Binary))
{
while (readStream.Position < readStream.Length)
{
buffer.Initialize();
// Reading stream
int bytesRead = readStream.Read(buffer, 0, BUFFER_SIZE);
// Writing stream
writeStream.Write(buffer, 0, bytesRead);
}
// flushing stream.
writeStream.Flush();
}
}
}
}
result = true;
return result;
}

JMS BytesMessage for sending multiple documents

I have a requirement for a batch job that should send out emails.However I have to break it out in such a fashion that I need to handover the email details to another system via messaging which will then read the messages placed and send out emails leisurely.
My emails have attachments.How do I achieve this? There could be multiple attachments for a given email.
I read about bytes message but how do I use it for multiple attachments for a given email message?
Any thoughts about this?
You could send one JMS message containing email details (from, to list, subject, text), and after that send attachments as JMS bytes message, each attachment message with the same custom identifier.
Sender side
// create JMS Bytes message with mail content
// MailData class should implement java.io.Serializable)
MailData mailData = new MailData();
// emailID could be GUID or anything else that would uniquely identify mail
mailData.setEmailID(emailID);
mailData.setFrom(from);
mailData.setToList(toList);
mailData.setSubject(subject);
mailData.setText(text);
BytesMessage msg = session.createBytesMessage();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(mailData);
out.close();
bos.close();
msg.writeBytes(bos.toByteArray());
producer.send(msg);
// for the sake of simplicity, object attachment contains attachment name, MIME type
// and value as byte array
for(Attachment att : attachmentList) {
BytesMessage msgAtt = session.createBytesMessage();
// emailID
msgAtt.setStringProperty("emailId", emailID);
msgAtt.setStringProperty("fileName", att.getAttachmentName());
msgAtt.setStringProperty("mimeType", att.getMimeType());
// set bytes message payload to attachment content
msgAtt.writeBytes(att.getValue());
producer.send(msgAtt);
}
Receiver side
BytesMessage bytesMessage = (BytesMessage) message;
byte[] bytes = new byte[(int) bytesMessage.getBodyLength()];
bytesMessage.readBytes(bytes);
ByteArrayInputStream bis = new ByteArrayInputStream(bytesMessage);
ObjectInputStream in = new ObjectInputStream(bis);
MailData mailData = (MailData) in.readObject();
in.close();
bis.close();
// get data from queue with the same emailID
MessageConsumer consumer = session.createConsumer(queue, "emailID='"
+ mailData.getEmailID() + "'");
connection.start();
Message attMsg = null;
while((attMsg = consumer.receiveNoWait()) != null) {
String fileName = attMsg.getStringProperty("fileName");
String mimeType = att.getStringProperty("mimeType");
BytesMessage bytesMessage = (BytesMessage) attMsg;
byte[] attachmentValue = new byte[(int) bytesMessage.getBodyLength()];
bytesMessage.readBytes(attachmentValue);
}

Resources