Good Morning,
I have been working on this project for a few days now and have ground to a halt. Downloading attachments seems to take forever and it would appear to be at the writing file to disk line. I have read about many options (FileChannel, bulk getContent and a few others but can not make this code execute at a reasonable rate) I am not to sure if the only bottle neck is the downloading of the files from O365 however I thought I would ask a question to see if somebody could review this code and hopefully tell me what I have done wrong. The goal of the application is to log into Exchange Online (o365) and download all attachments within a certain mail box. Please note that this code has been modified so many times to see if I could make performance increases by using threading and so on:
As I said I have shifted everything around a lot to try and make this work better so please don't blow me up for some of the code not making too much sense. I am not trying to get somebody else to finish this project, I am looking for guidance with a language that I do not have a great deal of experience with.
package o365connect;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.NoSuchProviderException;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeBodyPart;
/**
*
* #author Charlie
*/
public class AttDownload extends Thread {
public static int Lower = 0;
public static int Upper = 0;
public static int Counter = 0;
public static Session session;
public static Store store;
public static Properties props = new Properties();
public static boolean fTest = false;
AttDownload(int i, int ii) {
Lower = i;
Upper = ii;
}
AttDownload() throws UnknownHostException {
super();
}
#Override
public void run() {
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
String pop3Host = "outlook.office365.com";
String mailStoreType = "imap";
String path = "Inbox/Scans to file";
String userName = "XXX#XXX.com";
String password = "XXXXXXX";
Folder emailFolder;
try {
props.setProperty("mail.imaps.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.imaps.socketFactory.fallback", "false");
props.setProperty("mail.imaps.port", "993");
props.setProperty("mail.imaps.socketFactory.port", "993");
props.put("mail.imaps.host", "outlook.office365.com");
session = Session.getInstance(props);
int Size = functions.MBSize(pop3Host, userName, password, path);
System.out.println(Size);
store = session.getStore("imaps");
store.connect(pop3Host, userName, password);
emailFolder = store.getFolder(path);
emailFolder.open(Folder.READ_ONLY);
try {
Message[] messages;
messages = emailFolder.getMessages(Lower, Upper);
System.out.println("starting thread for - " + Lower + " - " + Upper);
int ASuc = receiveEmail(messages);
} catch (MessagingException | IOException ex) {
Logger.getLogger(AttDownload.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (NoSuchProviderException ex) {
Logger.getLogger(AttDownload.class.getName()).log(Level.SEVERE, null, ex);
} catch (MessagingException ex) {
Logger.getLogger(AttDownload.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static int receiveEmail(Message messagesarr[]) throws IOException, MessagingException {
for (Message messagesarr1 : messagesarr) {
try {
Message message = messagesarr1;
Object content = message.getContent();
if (content instanceof String) {
} else if (content instanceof Multipart) {
Multipart multipart = (Multipart) message.getContent();
for (int k = 0; k < multipart.getCount(); k++) {
MimeBodyPart bodyPart = (MimeBodyPart) multipart.getBodyPart(k);
if (Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) {
long startTime = System.currentTimeMillis();
int ran = (int) startTime;
String fileName;
String fName = bodyPart.getFileName();
if (fName != null && !fName.isEmpty()) {
fileName = fName.replaceAll("\\s+", "");
} else {
continue;
}
if ("ATT00001.txt".equals(fileName)) {
continue;
} else {
System.out.println("starting copy of - " + fileName);
}
String destFilePath = "D:/Scans/";
bodyPart.saveFile(destFilePath + bodyPart.getFileName());
long stopTime = System.currentTimeMillis();
System.out.println("finished copying of - " + fileName + " - " + (stopTime - startTime) + " miliseconds.");
System.out.println(Counter);
Counter++;
} else {
}
}
}
}catch (MessagingException e) {
System.out.println(e);
}
}
return 1;
}
}
Functions.java
package o365connect;
import javax.mail.Folder;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.Session;
import javax.mail.Store;
import static o365connect.AttDownload.store;
/**
*
* #author Oliver
*/
public class functions {
public static int TestUser(String pop3host, String Username, String Password) throws NoSuchProviderException, MessagingException {
try {
Session session = Session.getInstance(AttDownload.props);
store = session.getStore("imaps");
store.connect(pop3host, Username, Password);
return 0;
} catch (MessagingException e) {
System.out.println(e + "User Name Invalid");
return 1;
}
}
public static Folder TestFolder(Store store, String Path) throws MessagingException {
Folder emailFolder;
emailFolder = store.getFolder(Path);
emailFolder.open(Folder.READ_ONLY);
AttDownload.fTest = true;
emailFolder.close(false);
return emailFolder;
}
public static int MBSize(String pop3Host, String userName, String password, String Path) {
int Size = 0;
Session session = Session.getInstance(AttDownload.props);
try {
Store store = session.getStore("imaps");
store.connect(pop3Host, userName, password);
Folder emailFolder = store.getFolder(Path);
emailFolder.open(Folder.READ_ONLY);
Size = emailFolder.getMessageCount();
emailFolder.close(false);
store.close();
return Size;
} catch (MessagingException e) {
System.out.println(e + "MBSize");
}
return Size;
}
}
O365Connect.java
package o365connect;
import java.io.IOException;
import javax.mail.MessagingException;
public class O365Connect {
public static void main(String[] args) throws IOException, MessagingException, InterruptedException {
MainScreen ms = new MainScreen();
ms.setVisible(true);
AttDownload dl = new AttDownload(1, 1000);
dl.start();
}
}
Edit:
props.put("mail.imaps.fetchsize", "819200");
props.put("mail.imaps.partialfetch", "false");
sped things up, 128 seconds down to 12 seconds to download a 7mb file.
fetchsize is not used if partialfetch is false; it will download the entire attachment in one request. As long as you have enough memory for the largest possible attachment, that's fine. Otherwise, leave partialfetch set to true (default) and set the fetchsize large enough to give reasonable performance without using excessive memory.
JavaMail properties are described in the javadocs, on the page for each protocol provider. For example, the IMAP provider properties are described on the com.sun.mail.imap package javadoc page.
Related
I have a problem, I am using slack and mail.
I have got a method to create a folder with header "chan", but it doesn't work:
method getMessage()
for (String chan : channels){
sentMessage(chan);//поменять куда вставить
System.out.println(chan);
Enter:
"Что то пошло не такjavax.mail.MessagingException: Could not to SMTP host: localhost, port 25; nested exception is : java.net.Connection refused connect"
If I comment out
sentMessage(chan);//поменять куда вставить
I have got send message from slack to mail.
This is my program on java.
package ru.slacks;
import com.github.seratch.jslack.*;
import com.github.seratch.jslack.api.methods.SlackApiException;
import com.github.seratch.jslack.api.methods.request.channels.ChannelsListRequest;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.Scanner;
import com.github.seratch.jslack.api.methods.request.im.ImListRequest;
import com.ullink.slack.simpleslackapi.*;
import com.ullink.slack.simpleslackapi.SlackSession;
import com.ullink.slack.simpleslackapi.events.SlackMessagePosted;
import com.ullink.slack.simpleslackapi.impl.ChannelHistoryModuleFactory;
import static java.util.stream.Collectors.toList;
import com.ullink.slack.simpleslackapi.impl.SlackSessionFactory;
import org.glassfish.grizzly.http.server.util.StringParser;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.swing.*;
public class SlackTools {
public SlackTools() throws IOException, SlackApiException {
}
private String token=".....our_token......";
static final Slack slack = Slack.getInstance();
List<String> channels = slack.methods().channelsList(ChannelsListRequest.builder().token(token).build())
.getChannels().stream().map(c -> c.getId()).collect(toList());
public void getChannels() throws IOException, SlackApiException {
System.out.println("---------------Channels---------------");
for (String chan : channels){
sentMessage(chan);//поменять куда вставить
System.out.println(chan);
}
}
public class EmailAuthenticator extends javax.mail.Authenticator
{
private String login;
private String password;
public EmailAuthenticator (final String login, final String password)
{
this.login = login;
this.password = password;
}
public PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(login, password);
}
}
public void sentMessage(String chanel) throws IOException {
Properties imap = new Properties();
imap.put("mail.debug" , "false" );
imap.put("mail.store.protocol" , "imaps" );//для доступа и обработки сообщений
imap.put("mail.imap.ssl.enable", true);
imap.put("mail.imap.port", 993);
Authenticator auth = new EmailAuthenticator("tm12018#yandex.ru",
"test123456");
Session session = Session.getDefaultInstance(imap, auth);
session.setDebug(false);
try {
Store store = session.getStore();
// Подключение к почтовому серверу
store.connect("imap.yandex.ru", "tm12018#yandex.ru", "test123456");
// Папка входящих сообщений
Folder inbox = store.getFolder(chanel);
if (!inbox.exists())
if (inbox.create(Folder.HOLDS_MESSAGES))
System.out.println("Folder was created successfully");
// Открываем папку в режиме только для чтения
//inbox.open(Folder.READ_ONLY);
inbox.open(Folder.READ_WRITE);
System.out.println("Количество сообщений : " +
String.valueOf(inbox.getMessageCount()));
if (inbox.getMessageCount() == 0)
return;
} catch (NoSuchProviderException e) {
System.err.println(e.getMessage());
} catch (MessagingException e) {
System.err.println(e.getMessage());
}
}
public void getMessage() throws IOException {
Properties p = new Properties();
p.put("mail.smtp.host", "smtp.yandex.ru");//протокол передачи сообщений, или smtp.gmail.com
p.put("mail.smtp.socketFactory.port", 465);
p.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
p.put("mail.smtp.auth", true);
p.put("mail.smtp.port", 465);
// p.put("mail.transport.protocol", "smtp");
Scanner in = new Scanner(System.in);
System.out.print("Enter your e-mail ");
String user = in.nextLine();
System.out.println("Enter your password");
String password = in.nextLine();
Session s = Session.getDefaultInstance(p,
new Authenticator(){
protected PasswordAuthentication getPasswordAuthentication(){
return new PasswordAuthentication(user, password);}});
System.out.print("Enter usernameto ");
String userto = in.nextLine();
for(String chan : channels ){
SlackSession sessiont = SlackSessionFactory.createWebSocketSlackSession(token);
sessiont.connect();
ChannelHistoryModule channelHistoryModule = ChannelHistoryModuleFactory.createChannelHistoryModule(sessiont);
List<SlackMessagePosted> messages = channelHistoryModule.fetchHistoryOfChannel(chan).stream().collect(toList());
System.out.println("---------------Messages- " + chan + "--------------");
for (SlackMessagePosted message : messages) {
System.out.println("E-mail:" + message.getUser().getUserMail() + ", message: " + message.getMessageContent() );
try {
Message mess = new MimeMessage(s);
mess.setFrom(new InternetAddress(user));
mess.setRecipients(Message.RecipientType.TO, InternetAddress.parse(userto));
mess.setSubject(message.getMessageContent().toString());
mess.setText(chan);
Transport.send(mess);
JOptionPane.showMessageDialog(null, "Письмо отправлено" );
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "Что то пошло не так" + ex);
}
}
}
}
public static void main(String[] args) throws IOException, SlackApiException, MessagingException {
SlackTools sl = new SlackTools();
sl.getChannels();
sl.getMessage();
System.exit(0);
}
}
Looks like the response is telling you that there is no process (or at least not a email host) listening on your localhost port 25. Are you sure it's there? What happens when you do telnet localhost 25 ?
I was testing green mail api and received following error while trying to fetch from green mail server though server was correctly up.
I am using green mail 1.4.1, java 8, java mail 1.5.3.
Below is the code that i have been executing and the exception that i am receiving.
package greenmailtest;
import java.io.IOException;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import com.icegreen.greenmail.user.GreenMailUser;
import com.icegreen.greenmail.user.UserException;
import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.GreenMailUtil;
import com.icegreen.greenmail.util.ServerSetupTest;
public class ImapIT {
private static final String USER_PASSWORD = "abcdef123";
private static final String USER_NAME = "hascode";
private static final String EMAIL_USER_ADDRESS = "hascode#localhost";
private static final String EMAIL_TO = "someone#localhost.com";
private static final String EMAIL_SUBJECT = "Test E-Mail";
private static final String EMAIL_TEXT = "This is a test e-mail.";
private static final String LOCALHOST = "127.0.0.1";
private GreenMail mailServer;
public void setUp() {
mailServer = new GreenMail(ServerSetupTest.IMAP);
mailServer.start();
}
public void tearDown() {
mailServer.stop();
}
public void getMails() throws IOException, MessagingException,
UserException, InterruptedException {
// create user on mail server
GreenMailUser user = mailServer.setUser(EMAIL_USER_ADDRESS, USER_NAME,
USER_PASSWORD);
// create an e-mail message using javax.mail ..
MimeMessage message = new MimeMessage((Session) null);
message.setFrom(new InternetAddress(EMAIL_TO));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(
EMAIL_USER_ADDRESS));
message.setSubject(EMAIL_SUBJECT);
message.setText(EMAIL_TEXT);
// use greenmail to store the message
user.deliver(message);
// fetch the e-mail via imap using javax.mail ..
Properties props = new Properties();
props.put("mail.store.protocol", "imap");
Session session = Session.getInstance(props);
Store store = session.getStore();
store.connect(ServerSetupTest.IMAP.getBindAddress(), ServerSetupTest.IMAP.getPort(), user.getLogin(),
user.getPassword());
// store.connect();
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
Message[] messages = folder.getMessages();
for (Message m : messages) {
System.out.println("*** Class: " + m.getClass() + " ***");
System.out.println("From: " + m.getFrom()[0]);
System.out.println("To: " + m.getRecipients(Message.RecipientType.TO)[0]);
System.out.println("Subject: " + m.getSubject());
System.out.println("Content: " + m.getContent());
}
folder.close(true);
// assertNotNull(messages);
// assertThat(1, equalTo(messages.length));
// assertEquals(EMAIL_SUBJECT, messages[0].getSubject());
// assertTrue(String.valueOf(messages[0].getContent())
// .contains(EMAIL_TEXT));
// assertEquals(EMAIL_TO, messages[0].getFrom()[0].toString());
}
public static void main(String[]args){
ImapIT imap=new ImapIT();
imap.setUp();
try {
imap.getMails();
imap.tearDown();
} catch (IOException | MessagingException | UserException
| InterruptedException e) {
e.printStackTrace();
}
}
}
javax.mail.FolderClosedException: * BYE JavaMail
Exception:java.io.IOException: Connection dropped by server?
at com.sun.mail.imap.IMAPMessage.loadEnvelope(IMAPMessage.java:1428)
at com.sun.mail.imap.IMAPMessage.getFrom(IMAPMessage.java:321)
at greenmailtest.ImapIT.getMails(ImapIT.java:75)
at greenmailtest.ImapIT.main(ImapIT.java:93)
import com.sun.mail.pop3.POP3Folder;
import com.sun.mail.pop3.POP3SSLStore;
import javax.mail.Session;
import javax.mail.Flags;
import javax.mail.Message;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.StringTokenizer;
import javax.mail.internet.MimeMessage;
import java.io.FileOutputStream;
import java.io.File;
import java.io.ObjectOutputStream;
import java.io.Writer;
import java.net.URL;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.Store;
import javax.mail.Folder;
import java.util.Properties;
import javax.mail.URLName;
/**
* This class is responsible for deleting e-mails.
*
* #author Frank W. Zammetti.
*/public class deletemail {
private static final String SMTP_HOST_NAME = "smtp.gmail.com";
private static final int SMTP_HOST_PORT = 465;
private static final String SMTP_AUTH_USER = "examplemail#gmail.com";
private static final String SMTP_AUTH_PWD = "examplepassword";
private Session session;
private POP3SSLStore store;
private String username;
private String password;
private POP3Folder folder;
URLName url;
public static void main(String[] args) throws Exception{
new deletemail().test();
}
public void test() throws Exception{
try{
Properties pop3props = new Properties();
//----------------------------------------------
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties pop3Props = new Properties();
pop3Props.setProperty("mail.pop3.socketFactory.class", SSL_FACTORY);
pop3Props.setProperty("mail.pop3.socketFactory.fallback", "false");
pop3Props.setProperty("mail.pop3.port", "995");
pop3Props.setProperty("mail.pop3.socketFactory.port", "995");
username="examplemail#gmail.com";
password="examplepassword";
url = new URLName("pop3", "pop.gmail.com", 995, "", username, password);
session = Session.getInstance(pop3Props, null);
store = new POP3SSLStore(session, url);
store.connect();
folder = (POP3Folder) store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
Message message[] = folder.getMessages();
System.out.println(message.length);
for (int i=0, n=message.length; i<n; i++) {
message[i].setFlag(Flags.Flag.DELETED, true);
System.out.println("hello world");
}
folder.close(true);
store.close();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (folder != null) {
folder.close(true);
}
if (store != null) {
store.close();
}
} catch (Exception e) { }
}
}
}
let in first the in box contain 10 messages
message.length=10
after executing this program message.
length is get decresed to 0
but when i open my gmail account messaes
are still thereand they are not get deleted from the inbox
The problem is that GMail is not following IMAP convention of deleting emails.
According to https://javaee.github.io/javamail/FAQ#gmaildelete you have to:
Label message with flag [Gmail]/Trash,
Navigate to that label and set flag DELETED to true for that email,
Close folder (with expunge flag set to true).
Assuming that you have emails in array you have to do something like this:
Folder trashFolder = this.open("[Gmail]/Trash", true);
for (Message m : messages) {
m.getFolder().copyMessages(new Message[]{m}, trashFolder);
}
this.close(trashFolder, true);
trashFolder = this.open("[Gmail]/Trash", true);
for (Message m : trashFolder.getMessages()) {
m.setFlag(Flags.Flag.DELETED, true);
}
this.close(trashFolder, true);
This Gmail help page probably explains what's going on.
Is it possible to do file/directory sync in Java using JSch ? I need to sync directory from a remote linux machine to my local windows machine. Is this possible ?
-Tivakar
The easiest way to download files from SCP server is using Commons VFS along with JSch:
import java.io.*;
import org.apache.commons.io.FileUtils;
import org.apache.commons.vfs2.*;
public class CopyRemoteFile {
public static void copyRemoteFiles(String host, String user, String remotePath, String localPath) throws IOException {
FileSystemOptions fsOptions = new FileSystemOptions();
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fsOptions, "no");
SftpFileSystemConfigBuilder.getInstance().setIdentities(fsOptions,
new File[] { new File(FileUtils.getUserDirectoryPath() + "/.ssh/id_dsa") });
DefaultFileSystemManager fsManager = (DefaultFileSystemManager) VFS.getManager();
String uri = "sftp://" + user + "#" + host + "/" + remotePath;
FileObject fo = fsManager.resolveFile(uri, fsOptions);
FileObject[] files = fo.getChildren();
for (FileObject file : files) {
// We will be dealing with the files here only
if (file.getType() == FileType.FILE) {
FileUtils.copyInputStreamToFile(file.getContent().getInputStream(),
new File(localPath + "/" + file.getName().getBaseName()));
}
file.close();
}
fo.close();
fsManager.close();
}
}
It's just an example I got in my Wiki, so nothing fancy. But do keep in mind that if you'll close fsManager, you will not be able to open it again in the same VM. I got this issue while testing this solution...
Although the example above does not import any JSch classes, you need to put it in the classpath anyway.
The above example is using private key to authenticate with the remote host. You can easily change that by providing password and modifying the uri to include that.
If you need to sync files, you can compare dates of the files on the local file system (or DB, or any other source of the information) and the remote files:
import java.io.*;
import org.apache.commons.io.*;
import org.apache.commons.vfs2.*;
import org.apache.commons.vfs2.impl.*;
import org.apache.commons.vfs2.provider.sftp.*;
public class CopyRemoteFile {
public static void copyRemoteFiles(final String host, final String user, final String remotePath, final String localPath)
throws IOException {
FileSystemOptions fsOptions = new FileSystemOptions();
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fsOptions, "no");
SftpFileSystemConfigBuilder.getInstance().setIdentities(fsOptions,
new File[] { new File(FileUtils.getUserDirectoryPath() + "/.ssh/id_dsa") });
DefaultFileSystemManager fsManager = (DefaultFileSystemManager) VFS.getManager();
String uri = "sftp://" + user + "#" + host + "/" + remotePath;
FileObject fo = fsManager.resolveFile(uri, fsOptions);
FileObject[] files = fo.getChildren();
for (FileObject file : files) {
// We will be dealing with the files here only
File newFile = new File(localPath + "/" + file.getName().getBaseName());
if (file.getType() == FileType.FILE && newFile.lastModified() != file.getContent().getLastModifiedTime()) {
FileUtils.copyInputStreamToFile(file.getContent().getInputStream(), newFile);
newFile.setLastModified(file.getContent().getLastModifiedTime());
}
file.close();
}
fo.close();
fsManager.close();
}
}
Look at: http://the-project.net16.net/Projekte/projekte/Projekte/Programmieren/sftp-synchronisierung.html
There is a whole Programm uploadet.
Here is the sync Part:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Vector;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.SftpException;
/*
* This is the heart of the whole Program. I hope, the descriptions are precise enought.
*/
public class Sync{
public String ServerPath;
public File LocalFolder;
public sFTPclient client;
public ArrayList<String> serverContentList;
public ArrayList<String> pathList;
public Sync(File local, String to, sFTPclient client){
this.LocalFolder = local;
this.ServerPath = to;
this.client = client;
}
/*
* Executed once. Sets the Server Directory if it exists.
* If the local folder doesn't exist on the Server, it creates it.
*/
public void setServerDirectory() throws SftpException{
try{
client.sftpChannel.cd(ServerPath);
}catch(Exception e){
GUI.addToConsole(ServerPath + " don't exist on your server!");
}
String serverFolder = ServerPath.substring(ServerPath.lastIndexOf('/')+1, ServerPath.length());
if(!LocalFolder.getName().equals(serverFolder)){
try{
client.sftpChannel.mkdir(LocalFolder.getName());
client.sftpChannel.cd(LocalFolder.getName());
} catch (Exception e){
client.sftpChannel.cd(LocalFolder.getName());
}
this.ServerPath = ServerPath + "/" + LocalFolder.getName();
GUI.setNewServerFolder(ServerPath);
}
serverContentList = new ArrayList<String>();
pathList = new ArrayList<String>();
}
//The contentlist contains all Filenames, that should be synchronized
public void setToContentList(String ServerFolder) throws SftpException{
#SuppressWarnings("unchecked")
Vector<LsEntry> fileList = client.sftpChannel.ls(ServerFolder);
int size = fileList.size();
for(int i = 0; i < size; i++){
if(!fileList.get(i).getFilename().startsWith(".")){
serverContentList.add(fileList.get(i).getFilename());
pathList.add(ServerFolder);
}
}
}
/*
* Deletes the synchronized elements from the Lists
*/
public void deleteFromLists(String name){
int position = serverContentList.lastIndexOf(name);
if(position >= 0){
serverContentList.remove(position);
pathList.remove(position);
}
}
/*
* Main function for synchronizing. Works recursive for local folders.
*/
#SuppressWarnings("unchecked")
public void synchronize(File localFolder, String ServerDir) throws SftpException, FileNotFoundException{
if(client.sftpChannel.pwd() != ServerDir){
client.sftpChannel.cd(ServerDir);
}
setToContentList(ServerDir);
File[] localList = localFolder.listFiles();
Vector<LsEntry> ServerList = client.sftpChannel.ls(ServerDir);
ServerList.remove(0); ServerList.remove(0);
/*
* Upload missing Files/Folders
*/
int size = localList.length;
for(int i = 0; i < size; i++){
if(localList[i].isDirectory()){
if(checkFolder(localList[i], ServerDir)){
synchronize(localList[i], ServerDir + "/" + localList[i].getName());
deleteFromLists("SubFolder");
}else {
newFileMaster(true, localList[i], ServerDir);
}
} else {
checkFile(localList[i], ServerDir);
}
deleteFromLists(localList[i].getName());
}
}
/*
* Deletes all files on the server, which are not in the local Folder. Deletes also all missing folders
*/
public void deleteRest() throws SftpException, FileNotFoundException{
int size = serverContentList.size();
for(int i = 0; i < size; i++){
client.sftpChannel.cd(pathList.get(i));
newFileMaster(false, null, serverContentList.get(i));
}
}
/*
* Copy or delete Files/Folders
*/
public void newFileMaster(boolean copyOrNot, File sourcePath, String destPath) throws FileNotFoundException, SftpException{
FileMaster copy = new FileMaster(copyOrNot, sourcePath, destPath, client.sftpChannel);
copy.runMaster();
}
/*
*Useful to find errors - Prints out the content-List every time you call the method.
*If you have Problems, call it before and after every changes of the serverContentList!
*/
/*public void printServerContent(){
System.out.println("SERVER-Content: " + "\n");
for(int i = 0; i < serverContentList.size(); i++){
System.out.println(serverContentList.get(i) + " in " + pathList.get(i));
}
}*/
/*
* Looks ond the server, if the file is there. If not, or the local file has changed, it copies the file on the server.
*/
public void checkFile(File file, String path) throws SftpException, FileNotFoundException{
client.sftpChannel.cd(path);
if(!serverContentList.contains(file.getName())){
newFileMaster(true, file, ServerPath);
} else {
Long localTimeStamp = file.lastModified();
Long timeStamp = client.sftpChannel.stat(file.getName()).getATime()*1000L;
if(localTimeStamp > timeStamp){
newFileMaster(false, null, path + "/" + file.getName());
newFileMaster(true, file, path);
}
}
deleteFromLists(file.getName());
}
/*
* The same as the checkFile function. But it returns a boolean. (Easier to handle in the synchronized funtion)
* Don't check, if the folder has changed (I think this can't be the case)
*/
public boolean checkFolder(File folder, String path) throws SftpException{
client.sftpChannel.cd(path);
if(serverContentList.contains(folder.getName())){
return true;
}else { return false; }
}
}
I had a look in the reference doc, and Spring seems to have pretty good support for sending mail. However, I need to login to a mail account, read the messages, and download any attachments. Is downloading mail attachments supported by the Spring mail API?
I know you can do this with the Java Mail API, but in the past I've found that very verbose and unpleasant to work with.
EDIT: I've received several replies pointing towards tutorials that describe how to send mail with attachments, but what I'm asking about is how to read attachments from received mail.
Cheers,
Don
Here's the class that I use for downloading e-mails (with attachment handling). You'll have to glance by some of the stuff it's doing (like ignore the logging classes and database writes). I've also re-named some of the packages for ease of reading.
The general idea is that all attachments are saved as individual files in the filesystem, and each e-mail is saved as a record in the database with a set of child records that point to all of the attachment file paths.
Focus on the doEMailDownload method.
/**
* Copyright (c) 2008 Steven M. Cherry
* All rights reserved.
*/
package utils.scheduled;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.Timestamp;
import java.util.Properties;
import java.util.Vector;
import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeBodyPart;
import glob.ActionLogicImplementation;
import glob.IOConn;
import glob.log.Log;
import logic.utils.sql.Settings;
import logic.utils.sqldo.EMail;
import logic.utils.sqldo.EMailAttach;
/**
* This will connect to our incoming e-mail server and download any e-mails
* that are found on the server. The e-mails will be stored for further processing
* in our internal database. Attachments will be written out to separate files
* and then referred to by the database entries. This is intended to be run by
* the scheduler every minute or so.
*
* #author Steven M. Cherry
*/
public class DownloadEMail implements ActionLogicImplementation {
protected String receiving_host;
protected String receiving_user;
protected String receiving_pass;
protected String receiving_protocol;
protected boolean receiving_secure;
protected String receiving_attachments;
/** This will run our logic */
public void ExecuteRequest(IOConn ioc) throws Exception {
Log.Trace("Enter");
Log.Debug("Executing DownloadEMail");
ioc.initializeResponseDocument("DownloadEMail");
// pick up our configuration from the server:
receiving_host = Settings.getValue(ioc, "server.email.receiving.host");
receiving_user = Settings.getValue(ioc, "server.email.receiving.username");
receiving_pass = Settings.getValue(ioc, "server.email.receiving.password");
receiving_protocol = Settings.getValue(ioc, "server.email.receiving.protocol");
String tmp_secure = Settings.getValue(ioc, "server.email.receiving.secure");
receiving_attachments = Settings.getValue(ioc, "server.email.receiving.attachments");
// sanity check on the parameters:
if(receiving_host == null || receiving_host.length() == 0){
ioc.SendReturn();
ioc.Close();
Log.Trace("Exit");
return; // no host defined.
}
if(receiving_user == null || receiving_user.length() == 0){
ioc.SendReturn();
ioc.Close();
Log.Trace("Exit");
return; // no user defined.
}
if(receiving_pass == null || receiving_pass.length() == 0){
ioc.SendReturn();
ioc.Close();
Log.Trace("Exit");
return; // no pass defined.
}
if(receiving_protocol == null || receiving_protocol.length() == 0){
Log.Debug("EMail receiving protocol not defined, defaulting to POP");
receiving_protocol = "POP";
}
if(tmp_secure == null ||
tmp_secure.length() == 0 ||
tmp_secure.compareToIgnoreCase("false") == 0 ||
tmp_secure.compareToIgnoreCase("no") == 0
){
receiving_secure = false;
} else {
receiving_secure = true;
}
if(receiving_attachments == null || receiving_attachments.length() == 0){
Log.Debug("EMail receiving attachments not defined, defaulting to ./email/attachments/");
receiving_attachments = "./email/attachments/";
}
// now do the real work.
doEMailDownload(ioc);
ioc.SendReturn();
ioc.Close();
Log.Trace("Exit");
}
protected void doEMailDownload(IOConn ioc) throws Exception {
// Create empty properties
Properties props = new Properties();
// Get the session
Session session = Session.getInstance(props, null);
// Get the store
Store store = session.getStore(receiving_protocol);
store.connect(receiving_host, receiving_user, receiving_pass);
// Get folder
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
try {
// Get directory listing
Message messages[] = folder.getMessages();
for (int i=0; i < messages.length; i++) {
// get the details of the message:
EMail email = new EMail();
email.fromaddr = messages[i].getFrom()[0].toString();
Address[] to = messages[i].getRecipients(Message.RecipientType.TO);
email.toaddr = "";
for(int j = 0; j < to.length; j++){
email.toaddr += to[j].toString() + "; ";
}
Address[] cc;
try {
cc = messages[i].getRecipients(Message.RecipientType.CC);
} catch (Exception e){
Log.Warn("Exception retrieving CC addrs: %s", e.getLocalizedMessage());
cc = null;
}
email.cc = "";
if(cc != null){
for(int j = 0; j < cc.length; j++){
email.cc += cc[j].toString() + "; ";
}
}
email.subject = messages[i].getSubject();
if(messages[i].getReceivedDate() != null){
email.received_when = new Timestamp(messages[i].getReceivedDate().getTime());
} else {
email.received_when = new Timestamp( (new java.util.Date()).getTime());
}
email.body = "";
Vector<EMailAttach> vema = new Vector<EMailAttach>();
Object content = messages[i].getContent();
if(content instanceof java.lang.String){
email.body = (String)content;
} else if(content instanceof Multipart){
Multipart mp = (Multipart)content;
for (int j=0; j < mp.getCount(); j++) {
Part part = mp.getBodyPart(j);
String disposition = part.getDisposition();
if (disposition == null) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType("text/plain")) {
Log.Debug("Mime type is plain");
email.body += (String)mbp.getContent();
} else {
Log.Debug("Mime type is not plain");
// Special non-attachment cases here of
// image/gif, text/html, ...
EMailAttach ema = new EMailAttach();
ema.name = decodeName(part.getFileName());
File savedir = new File(receiving_attachments);
savedir.mkdirs();
File savefile = File.createTempFile("emailattach", ".atch", savedir );
ema.path = savefile.getAbsolutePath();
ema.size = part.getSize();
vema.add(ema);
ema.size = saveFile(savefile, part);
}
} else if ((disposition != null) &&
(disposition.equals(Part.ATTACHMENT) || disposition.equals(Part.INLINE) )
){
// Check if plain
MimeBodyPart mbp = (MimeBodyPart)part;
if (mbp.isMimeType("text/plain")) {
Log.Debug("Mime type is plain");
email.body += (String)mbp.getContent();
} else {
Log.Debug("Save file (%s)", part.getFileName() );
EMailAttach ema = new EMailAttach();
ema.name = decodeName(part.getFileName());
File savedir = new File(receiving_attachments);
savedir.mkdirs();
File savefile = File.createTempFile("emailattach", ".atch", savedir );
ema.path = savefile.getAbsolutePath();
ema.size = part.getSize();
vema.add(ema);
ema.size = saveFile( savefile, part);
}
}
}
}
// Insert everything into the database:
logic.utils.sql.EMail.insertEMail(ioc, email);
for(int j = 0; j < vema.size(); j++){
vema.get(j).emailid = email.id;
logic.utils.sql.EMail.insertEMailAttach(ioc, vema.get(j) );
}
// commit this message and all of it's attachments
ioc.getDBConnection().commit();
// Finally delete the message from the server.
messages[i].setFlag(Flags.Flag.DELETED, true);
}
// Close connection
folder.close(true); // true tells the mail server to expunge deleted messages.
store.close();
} catch (Exception e){
folder.close(true); // true tells the mail server to expunge deleted messages.
store.close();
throw e;
}
}
protected int saveFile(File saveFile, Part part) throws Exception {
BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(saveFile) );
byte[] buff = new byte[2048];
InputStream is = part.getInputStream();
int ret = 0, count = 0;
while( (ret = is.read(buff)) > 0 ){
bos.write(buff, 0, ret);
count += ret;
}
bos.close();
is.close();
return count;
}
protected String decodeName( String name ) throws Exception {
if(name == null || name.length() == 0){
return "unknown";
}
String ret = java.net.URLDecoder.decode( name, "UTF-8" );
// also check for a few other things in the string:
ret = ret.replaceAll("=\\?utf-8\\?q\\?", "");
ret = ret.replaceAll("\\?=", "");
ret = ret.replaceAll("=20", " ");
return ret;
}
}
I worked Steven's example a little bit and removed the parts of the code specific to Steven. My code won't read the body of an email if it has attachments. That is fine for my case but you may want to refine it further for yours.
package utils;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.mail.Address;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.MimeBodyPart;
public class IncomingMail {
public static List<Email> downloadPop3(String host, String user, String pass, String downloadDir) throws Exception {
List<Email> emails = new ArrayList<Email>();
// Create empty properties
Properties props = new Properties();
// Get the session
Session session = Session.getInstance(props, null);
// Get the store
Store store = session.getStore("pop3");
store.connect(host, user, pass);
// Get folder
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
try {
// Get directory listing
Message messages[] = folder.getMessages();
for (int i = 0; i < messages.length; i++) {
Email email = new Email();
// from
email.from = messages[i].getFrom()[0].toString();
// to list
Address[] toArray = messages[i] .getRecipients(Message.RecipientType.TO);
for (Address to : toArray) { email.to.add(to.toString()); }
// cc list
Address[] ccArray = null;
try {
ccArray = messages[i] .getRecipients(Message.RecipientType.CC);
} catch (Exception e) { ccArray = null; }
if (ccArray != null) {
for (Address c : ccArray) {
email.cc.add(c.toString());
}
}
// subject
email.subject = messages[i].getSubject();
// received date
if (messages[i].getReceivedDate() != null) {
email.received = messages[i].getReceivedDate();
} else {
email.received = new Date();
}
// body and attachments
email.body = "";
Object content = messages[i].getContent();
if (content instanceof java.lang.String) {
email.body = (String) content;
} else if (content instanceof Multipart) {
Multipart mp = (Multipart) content;
for (int j = 0; j < mp.getCount(); j++) {
Part part = mp.getBodyPart(j);
String disposition = part.getDisposition();
if (disposition == null) {
MimeBodyPart mbp = (MimeBodyPart) part;
if (mbp.isMimeType("text/plain")) {
// Plain
email.body += (String) mbp.getContent();
}
} else if ((disposition != null) && (disposition.equals(Part.ATTACHMENT) || disposition .equals(Part.INLINE))) {
// Check if plain
MimeBodyPart mbp = (MimeBodyPart) part;
if (mbp.isMimeType("text/plain")) {
email.body += (String) mbp.getContent();
} else {
EmailAttachment attachment = new EmailAttachment();
attachment.name = decodeName(part.getFileName());
File savedir = new File(downloadDir);
savedir.mkdirs();
// File savefile = File.createTempFile( "emailattach", ".atch", savedir);
File savefile = new File(downloadDir,attachment.name);
attachment.path = savefile.getAbsolutePath();
attachment.size = saveFile(savefile, part);
email.attachments.add(attachment);
}
}
} // end of multipart for loop
} // end messages for loop
emails.add(email);
// Finally delete the message from the server.
messages[i].setFlag(Flags.Flag.DELETED, true);
}
// Close connection
folder.close(true); // true tells the mail server to expunge deleted messages
store.close();
} catch (Exception e) {
folder.close(true); // true tells the mail server to expunge deleted
store.close();
throw e;
}
return emails;
}
private static String decodeName(String name) throws Exception {
if (name == null || name.length() == 0) {
return "unknown";
}
String ret = java.net.URLDecoder.decode(name, "UTF-8");
// also check for a few other things in the string:
ret = ret.replaceAll("=\\?utf-8\\?q\\?", "");
ret = ret.replaceAll("\\?=", "");
ret = ret.replaceAll("=20", " ");
return ret;
}
private static int saveFile(File saveFile, Part part) throws Exception {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(saveFile));
byte[] buff = new byte[2048];
InputStream is = part.getInputStream();
int ret = 0, count = 0;
while ((ret = is.read(buff)) > 0) {
bos.write(buff, 0, ret);
count += ret;
}
bos.close();
is.close();
return count;
}
}
You also need these two helper classes
package utils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Email {
public Date received;
public String from;
public List<String> to = new ArrayList<String>();
public List<String> cc = new ArrayList<String>();
public String subject;
public String body;
public List<EmailAttachment> attachments = new ArrayList<EmailAttachment>();
}
and
package utils;
public class EmailAttachment {
public String name;
public String path;
public int size;
}
I used this to test the above classes
package utils;
import java.util.List;
public class Test {
public static void main(String[] args) {
String host = "some host";
String user = "some user";
String pass = "some pass";
String downloadDir = "/Temp";
try {
List<Email> emails = IncomingMail.downloadPop3(host, user, pass, downloadDir);
for ( Email email : emails ) {
System.out.println(email.from);
System.out.println(email.subject);
System.out.println(email.body);
List<EmailAttachment> attachments = email.attachments;
for ( EmailAttachment attachment : attachments ) {
System.out.println(attachment.path+" "+attachment.name);
}
}
} catch (Exception e) { e.printStackTrace(); }
}
}
More info can be found at http://java.sun.com/developer/onlineTraining/JavaMail/contents.html
Here is an error:
else if ((disposition != null) && (disposition.equals(Part.ATTACHMENT)
|| disposition.equals(Part.INLINE) )
it should be:
else if ((disposition.equalsIgnoreCase(Part.ATTACHMENT)
|| disposition.equalsIgnoreCase(Part.INLINE))
Thanks #Stevenmcherry for your answer
I used Apache Commons Mail for this task:
import java.util.List;
import javax.activation.DataSource;
import javax.mail.internet.MimeMessage;
import org.apache.commons.mail.util.MimeMessageParser;
public List<DataSource> getAttachmentList(MimeMessage message) throws Exception {
msgParser = new MimeMessageParser(message);
msgParser.parse();
return msgParser.getAttachmentList();
}
From a DataSource object you can retrieve an InputStream (beside name and type) of the attachment (see API: http://docs.oracle.com/javase/6/docs/api/javax/activation/DataSource.html?is-external=true).
Thus far, I've only used the JavaMail APIs (and I've been reasonably happy with them for my purposes). If the full JavaMail package is too heavy for you, the underlying transport engine can be used without the top layers of the package. The lower you go in the SMTP, POP3 and IMAP stacks, the more you have to be prepared to do for yourself.
On the bright side, you'll also be able to ignore the parts that aren't required for your application.
import java.io.IOException;
import java.io.InputStream;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamSource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
#Controller
#RequestMapping("/sendEmail.do")
public class SendEmailAttachController {
#Autowired
private JavaMailSender mailSender;
#RequestMapping(method = RequestMethod.POST)
public String sendEmail(HttpServletRequest request,
final #RequestParam CommonsMultipartFile attachFile) {
// Input here
final String emailTo = request.getParameter("mailTo");
final String subject = request.getParameter("subject");
final String yourmailid = request.getParameter("yourmail");
final String message = request.getParameter("message");
// Logging
System.out.println("emailTo: " + emailTo);
System.out.println("subject: " + subject);
System.out.println("Your mail id is: "+yourmailid);
System.out.println("message: " + message);
System.out.println("attachFile: " + attachFile.getOriginalFilename());
mailSender.send(new MimeMessagePreparator() {
#Override
public void prepare(MimeMessage mimeMessage) throws Exception {
MimeMessageHelper messageHelper = new MimeMessageHelper(
mimeMessage, true, "UTF-8");
messageHelper.setTo(emailTo);
messageHelper.setSubject(subject);
messageHelper.setReplyTo(yourmailid);
messageHelper.setText(message);
// Attachment with mail
String attachName = attachFile.getOriginalFilename();
if (!attachFile.equals("")) {
messageHelper.addAttachment(attachName, new InputStreamSource() {
#Override
public InputStream getInputStream() throws IOException {
return attachFile.getInputStream();
}
});
}
}
});
return "Result";
}
}