net.fenyo.mail4hotspot.service.MailManager.java Source code

Java tutorial

Introduction

Here is the source code for net.fenyo.mail4hotspot.service.MailManager.java

Source

// (c) Alexandre Fenyo 2012, 2013, 2014, 2015, 2016 - alex@fenyo.net - http://fenyo.net - GPLv3 licensed

package net.fenyo.mail4hotspot.service;

import java.io.IOException;
import java.util.Properties;

import javax.mail.*;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.net.ssl.*;

import org.apache.commons.lang3.ArrayUtils;
import net.fenyo.mail4hotspot.domain.*;
import net.fenyo.mail4hotspot.tools.GenericTools;

// pour rajouter un certificat au keystore global :
// on va dans le rept contenant le keystore global cacerts :
// cd "/cygdrive/c/Program Files/Java/jdk1.7.0_01/jre/lib/security"
// on rajouter un password :
// c:/Program\ Files/Java/jdk1.7.0_01/jre/bin/keytool.exe -protected -storepasswd -keystore cacerts
// on rajouter le certif  l'aide de ce password :
// c:/Program\ Files/Java/jdk1.7.0_01/jre/bin/keytool.exe -importcert -file cyrus-CAcert.pem -alias rsi -storepass PASSWORD -keystore cacerts
// si on ne prcisait pas le keystore, un nouveau serait cr : C:\Documents and Settings\fenyo.C01078599\.keystore

///usr/lib/cyrus/bin/deliver -e -r fenyo fenyo
//From: fenyo
//To: fenyo
//Subject: zefpozekfze
//
//test

//From: John Doe <example@example.com>
//MIME-Version: 1.0
//Content-Type: multipart/mixed;
//        boundary="XXXXboundary text"
//
//This is a multipart message in MIME format.
//
//--XXXXboundary text 
//Content-Type: text/plain
//
//this is the body text
//
//--XXXXboundary text 
//Content-Type: text/plain;
//Content-Disposition: attachment;
//        filename="test.txt"
//
//this is the attachment text
//
//--XXXXboundary text--

//MIME-Version: 1.0
//Content-Type: multipart/mixed; boundary=frontier
//
//This is a message with multiple parts in MIME format.
//--frontier
//Content-Type: text/plain
//
//This is the body of the message.
//--frontier
//Content-Type: application/octet-stream
//Content-Transfer-Encoding: base64
//
//PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
//Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg=
//--frontier--

// Subject: =?iso-8859-1?Q?=A1Hola,_se=F1or!?=
// correspond  Subject: Hola, seor!

// http://en.wikipedia.org/wiki/MIME

//MIME-Version: 1.0
//From: Nathaniel Borenstein 
//Subject: A multipart example
//Content-Type: multipart/mixed;
//                 boundary=unique-boundary-1
//
//This is the preamble area of a multipart message.  Mail readers
//that understand multipart format should ignore this preamble.
//
//If you are reading this text, you might want to consider
//changing to a mail reader that understands how to properly
//display multipart messages.
//--unique-boundary-1
//
//Some text appears here...
//[Note that the preceding blank line means
//no header fields were given and this is text,
//with charset US ASCII.  It could have been
//done with explicit typing as in the next part.]
//--unique-boundary-1
//Content-type: text/plain; charset=US-ASCII
//
//This could have been part of the previous part, but illustrates
//explicit versus implicit typing of body parts.
//
//--unique-boundary-1
//Content-Type: multipart/parallel; boundary=unique-boundary-2
//
//--unique-boundary-2
//Content-Type: audio/basic
//Content-Transfer-Encoding: base64
//
//... base64-encoded 8000 Hz single-channel u-law-format audio data
//goes here ...
//
//--unique-boundary-2
//Content-Type: image/gif
//Content-Transfer-Encoding: Base64
//
//... base64-encoded image data goes here ...
//
//--unique-boundary-2--
//
//--unique-boundary-1
//Content-type: text/richtext
//
//This is richtext.Isn't it
//cool?
//
//--unique-boundary-1
//Content-Type: message/rfc822
//
//From: (name in US-ASCII)
//Subject: (subject in US-ASCII)
//Content-Type: Text/plain; charset=ISO-8859-1
//Content-Transfer-Encoding: Quoted-printable
//
//... Additional text in ISO-8859-1 goes here ...
//
//--unique-boundary-1--

public class MailManager {
    protected final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(getClass());

    private javax.mail.Session session = null;
    private Store store = null;
    private Folder inbox = null;
    private Message[] messages = null;

    private Transport transport = null;

    public MailManager() {
    }

    private void connectToOutgoingServer(final String protocol, final String host, final int port,
            final String username, final String password) throws MessagingException {
        final Properties prop = new Properties();
        prop.setProperty("mail.mime.address.strict", "false");

        // prop.put("mail.smtp.auth", "true"); mais a laisse useAuth false
        prop.put("mail.smtp.starttls.enable", "true");

        prop.setProperty("mail.debug", "true");
        session = javax.mail.Session.getInstance(prop, null);
        session.setDebugOut(System.out);
        //session.setDebug(false);
        session.setDebug(true);

        transport = session.getTransport(protocol);
        transport.connect(host, username, password);
    }

    private void connectToServer(final String protocol, final String host, final int port, final String username,
            final String password) throws MessagingException {
        final Properties prop = new Properties();
        prop.setProperty("mail.mime.address.strict", "false");

        //      prop.setProperty(" mail.debug", "true");
        session = javax.mail.Session.getInstance(prop, null);

        //session.setDebugOut(System.out);
        //session.setDebug(false);
        //      session.setDebug(true);

        store = session.getStore(protocol);
        store.connect(host, port, username, password);
        inbox = store.getDefaultFolder().getFolder("INBOX");
        inbox.open(Folder.READ_ONLY);
        messages = inbox.getMessages();
    }

    public Message[] getMessages() {
        return messages;
    }

    public String getMessageContentString(final Message message) throws IOException, MessagingException {
        final Object content = message.getContent();
        if (String.class.isInstance(content))
            // content-type: text/{plain, html, etc.}
            // prfrer isMimeType(...)  getContentType().equals(...) car getContentType() peut contenir aussi le charset et renvoyer une string comme suit : << text/html; charset="us-ascii" >>
            if (message.isMimeType("text/html"))
                return GenericTools.html2Text((String) content);
            else if (message.isMimeType("text/plain"))
                return (String) content;
            else {
                log.warn("message content-type not handled: " + message.getContentType()
                        + " -> downgrading to String");
                return (String) content;
            }
        else if (MimeMultipart.class.isInstance(content)) {
            boolean mixed = false;
            if (message.isMimeType("multipart/mixed"))
                mixed = true;
            else if (message.isMimeType("multipart/alternative"))
                mixed = false;
            else {
                log.warn("multipart content-type not handled: " + message.getContentType()
                        + " -> downgrading to multipart/mixed");
                mixed = true;
            }
            return getMultipartContentString((MimeMultipart) content, mixed);
        } else {
            log.warn("invalid message content type and class: " + content.getClass().toString() + " - "
                    + message.getContentType());
            return "";
        }
    }

    private String getMultipartContentString(final MimeMultipart multipart, final boolean mixed)
            throws IOException, MessagingException {
        // content-type: multipart/mixed ou multipart/alternative

        final StringBuffer selected_content = new StringBuffer();
        for (int i = 0; i < multipart.getCount(); i++) {
            final BodyPart body_part = multipart.getBodyPart(i);
            final Object content = body_part.getContent();

            final String content_string;
            if (String.class.isInstance(content))
                if (body_part.isMimeType("text/html"))
                    content_string = GenericTools.html2Text((String) content);
                else if (body_part.isMimeType("text/plain"))
                    content_string = (String) content;
                else {
                    log.warn("body part content-type not handled: " + body_part.getContentType()
                            + " -> downgrading to String");
                    content_string = (String) content;
                }
            else if (MimeMultipart.class.isInstance(content)) {
                boolean part_mixed = false;
                if (body_part.isMimeType("multipart/mixed"))
                    part_mixed = true;
                else if (body_part.isMimeType("multipart/alternative"))
                    part_mixed = false;
                else {
                    log.warn("body part content-type not handled: " + body_part.getContentType()
                            + " -> downgrading to multipart/mixed");
                    part_mixed = true;
                }
                content_string = getMultipartContentString((MimeMultipart) content, part_mixed);
            } else {
                log.warn("invalid body part content type and class: " + content.getClass().toString() + " - "
                        + body_part.getContentType());
                content_string = "";
            }

            if (mixed == false) {
                // on slectionne la premire part non vide - ce n'est pas forcment la meilleure alternative, mais comment diffrentiel un text/plain d'une pice jointe d'un text/plain du corps du message, accompagnant un text/html du mme corps ???
                if (selected_content.length() == 0)
                    selected_content.append(content_string);
            } else {
                if (selected_content.length() > 0 && content_string.length() > 0)
                    selected_content.append("\r\n---\r\n");
                selected_content.append(content_string);
            }
        }
        return selected_content.toString();
    }

    private void connectToSMTPServer(final String host, final int port, final String username,
            final String password) throws MessagingException {
        connectToOutgoingServer("smtp", host, port, username, password);
    }

    private void connectToSMTPsServer(final String host, final int port, final String username,
            final String password) throws MessagingException {
        connectToOutgoingServer("smtps", host, port, username, password);
    }

    private void connectToPop3SSLServer(final String host, final int port, final String username,
            final String password) throws MessagingException {
        connectToServer("pop3s", host, port, username, password);
    }

    private void connectToPop3Server(final String host, final int port, final String username,
            final String password) throws MessagingException {
        connectToServer("pop3", host, port, username, password);
    }

    private void connectToImapServer(final String host, final int port, final String username,
            final String password) throws MessagingException {
        connectToServer("imap", host, port, username, password);
    }

    private void connectToImapSSLServer(final String host, final int port, final String username,
            final String password) throws MessagingException {
        connectToServer("imaps", host, port, username, password);
    }

    public void connectToProvider(final Account.Provider provider, final String username, final String password)
            throws MessagingException {
        // il faut rajouter dans le client AOL puis tester l'algo de la marque
        if (provider == Account.Provider.AOL)
            connectToPop3SSLServer("pop.aol.com.", 995, username, password);

        // GMail test OK pour la rception avec l'algo de la marque
        // en production : en imap - pour tester : en pop
        // if (provider == Account.Provider.GMAIL) connectToPop3SSLServer("pop.gmail.com.", 995, username, password);
        // protocole version 2 : rception OK
        if (provider == Account.Provider.GMAIL)
            connectToImapSSLServer("imap.gmail.com.", 993, username, password);

        // HotMail inclut outlook.com et live.com
        // HotMail test OK pour la rception avec l'algo de la marque
        // protocole version 2 : rception OK
        // if (provider == Account.Provider.HOTMAIL) connectToPop3SSLServer("pop3.live.com.", 995, username, password);
        if (provider == Account.Provider.HOTMAIL)
            connectToImapSSLServer("imap-mail.outlook.com.", 993, username, password);

        // YahooMail test OK pour la rception avec l'algo de la marque
        // MARCHE PAS EN AUTOMATIQUE en POP3S (le password n'est pas pris ou reconnu, l'change login/passwd semble planter car le passwd est envoy sans attendre le OK de la commande du login)
        // => ont fait en POP3
        //if (provider == Account.Provider.YAHOO) connectToPop3Server("pop.mail.yahoo.com.", 110, username, password);
        // protocole version 2 : rception OK (corrige en passant de pop  imaps)
        if (provider == Account.Provider.YAHOO)
            connectToImapSSLServer("imap.mail.yahoo.com.", 993, username, password);

        // OperaMail correspond  FastMail
        // OperaMail test OK pour la rception avec l'algo de la marque
        // protocole version 2 : rception OK
        if (provider == Account.Provider.OPERAMAIL)
            connectToImapSSLServer("mail.messagingengine.com.", 993, username, password);

        if (provider == Account.Provider.TESTIMAPLOCALHOST)
            connectToImapServer("localhost", 143, username, password);
        if (provider == Account.Provider.TESTIMAPRSI)
            connectToImapServer("10.69.60.6", 143, username, password);
        if (provider == Account.Provider.TESTPOPLOCALHOST)
            connectToPop3Server("localhost", 110, username, password);
        if (provider == Account.Provider.TESTPOPRSI)
            connectToPop3Server("10.69.60.6", 110, username, password);
    }

    public void connectToRelay(final Account.Provider provider, final String username, final String password)
            throws MessagingException {
        // il faut rajouter dans le client AOL puis tester
        if (provider == Account.Provider.AOL)
            connectToSMTPsServer("pop.aol.com.", 465, username, password);

        // test OK
        // protocole version 2 :  retester
        // mission : "DEBUG SMTP: useEhlo true, useAuth false" et version de JavaMail  regarder (1.5.4 : https://java.net/projects/javamail/pages/Home)
        //            et regarder les spcificits de JavaMail pour les diffrents providers : https://java.net/projects/javamail/pages/Home et " Q: How do I access Yahoo! Mail with JavaMail? " sur http://www.oracle.com/technetwork/java/javamail/faq/index.html#yahoomail
        // voir aussi l'exemple ici : https://community.oracle.com/thread/2350165?tstart=0
        // protocole version 2 : test OK
        if (provider == Account.Provider.GMAIL)
            connectToSMTPsServer("smtp.gmail.com.", 465, username, password);

        // test OK
        // protocole version 2 : test OK
        // if (provider == Account.Provider.HOTMAIL) connectToSMTPServer("smtp.live.com.", 25, username, password);
        if (provider == Account.Provider.HOTMAIL)
            connectToSMTPServer("smtp-mail.outlook.com.", 25, username, password);

        // test OK
        // protocole version 2 : test OK
        if (provider == Account.Provider.YAHOO)
            connectToSMTPsServer("smtp.mail.yahoo.com.", 465, username, password);

        // protocole version 2 : test OK
        if (provider == Account.Provider.OPERAMAIL)
            connectToSMTPsServer("mail.messagingengine.com.", 995, username, password);

        // ICI
    }

    public void disconnect() throws MessagingException {
        try {
            if (inbox != null)
                inbox.close(false);
        } finally {
            if (store != null)
                store.close();
        }
    }

    public void disconnectRelay() throws MessagingException {
        if (transport != null)
            transport.close();
    }

    public void sendMessage(Address from_addr, Address[] to_addr, Address[] cc_addr, String subject, String content)
            throws MessagingException {
        final MimeMessage msg = new MimeMessage(session);

        msg.setFrom(from_addr);
        msg.setRecipients(Message.RecipientType.TO, to_addr);
        if (cc_addr.length > 0)
            msg.setRecipients(Message.RecipientType.CC, cc_addr);
        msg.setSubject(subject, "UTF-8");
        msg.setContent(content, "text/plain");

        transport.sendMessage(msg, ArrayUtils.addAll(to_addr, cc_addr));
    }

    // marche uniquement pour les connexions HTTPs, pas pour pop3s ni smtps
    public static void trustSSL() {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            }

            public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
            }
        } };

        // c'est un pb de scurit, il faudrait mettre  jour les certifs racine et supprimer le all-trusting trust manager
        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            System.out.println("Can not install the all-trusting trust manager");
        }
    }

    // http://javamail.kenai.com/nonav/javadocs/
    // http://code.google.com/p/tubesrus/source/browse/trunk/src/tubesrus/beans/MailManager.java?spec=svn88&r=88
    public static void main(String[] args) throws NoSuchProviderException, MessagingException {
        System.out.println("Salut");

        //      trustSSL();

        /*       final Properties props = new Properties();
               props.put("mail.smtp.host", "my-mail-server");
               props.put("mail.from", "me@example.com");
               javax.mail.Session session = javax.mail.Session.getInstance(props, null);
               try {
          MimeMessage msg = new MimeMessage(session);
          msg.setFrom();
          msg.setRecipients(Message.RecipientType.TO,
                            "you@example.com");
          msg.setSubject("JavaMail hello world example");
          msg.setSentDate(new Date());
          msg.setText("Hello, world!\n");
          Transport.send(msg);
                  } catch (MessagingException mex) {
          System.out.println("send failed, exception: " + mex);
                  }*/

        final Properties props = new Properties();

        //props.put("mail.host", "10.69.60.6");
        //props.put("mail.user", "fenyo");
        //props.put("mail.from", "fenyo@fenyo.net");
        //props.put("mail.transport.protocol", "smtps");

        //props.put("mail.store.protocol", "pop3s");

        // [javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Sun Microsystems, Inc],
        // javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Sun Microsystems, Inc],
        // javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Sun Microsystems, Inc],
        // javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Sun Microsystems, Inc],
        // javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Sun Microsystems, Inc],
        // javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Sun Microsystems, Inc]]
        // final Provider[] providers = session.getProviders();

        javax.mail.Session session = javax.mail.Session.getInstance(props, null);

        session.setDebug(true);
        //session.setDebug(false);

        //       final Store store = session.getStore("pop3s");
        //       store.connect("10.69.60.6", 995, "fenyo", "PASSWORD");
        //       final Store store = session.getStore("imaps");
        //       store.connect("10.69.60.6", 993, "fenyo", "PASSWORD");
        //       System.out.println(store.getDefaultFolder().getMessageCount());

        //final Store store = session.getStore("pop3");
        final Store store = session.getStore("pop3s");
        //final Store store = session.getStore("imaps");

        //       store.addStoreListener(new StoreListener() {
        //          public void notification(StoreEvent e) {
        //          String s;
        //          if (e.getMessageType() == StoreEvent.ALERT)
        //          s = "ALERT: ";
        //          else
        //          s = "NOTICE: ";
        //          System.out.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX: " + s + e.getMessage());
        //          }
        //       });

        //store.connect("10.69.60.6", 110, "fenyo", "PASSWORD");
        store.connect("pop.gmail.com", 995, "alexandre.fenyo@gmail.com", "PASSWORD");
        //store.connect("localhost", 110, "alexandre.fenyo@yahoo.com", "PASSWORD");
        //store.connect("localhost", 995, "fenyo@live.fr", "PASSWORD");
        //store.connect("localhost", 995, "thisisatestforalex@aol.fr", "PASSWORD");

        //       final Folder[] folders = store.getPersonalNamespaces();
        //       for (Folder f : folders) {
        //          System.out.println("Folder: " + f.getMessageCount());
        //          final Folder g = f.getFolder("INBOX");
        //          g.open(Folder.READ_ONLY);
        //          System.out.println("   g:" + g.getMessageCount());
        //       }

        final Folder inbox = store.getDefaultFolder().getFolder("INBOX");
        inbox.open(Folder.READ_ONLY);
        System.out.println("nmessages: " + inbox.getMessageCount());

        final Message[] messages = inbox.getMessages();

        for (Message message : messages) {
            System.out.println("message:");
            System.out.println("  size: " + message.getSize());
            try {
                if (message.getFrom() != null)
                    System.out.println("  From: " + message.getFrom()[0]);
            } catch (final Exception ex) {
                System.out.println(ex.toString());
            }
            System.out.println("  content-type: " + message.getContentType());
            System.out.println("  disposition: " + message.getDisposition());
            System.out.println("  description: " + message.getDescription());
            System.out.println("  filename: " + message.getFileName());
            System.out.println("  line count: " + message.getLineCount());
            System.out.println("  message number: " + message.getMessageNumber());
            System.out.println("  subject: " + message.getSubject());
            try {
                if (message.getAllRecipients() != null)
                    for (Address address : message.getAllRecipients())
                        System.out.println("  address: " + address);
            } catch (final Exception ex) {
                System.out.println(ex.toString());
            }
        }

        for (Message message : messages) {
            System.out.println("-----------------------------------------------------");
            Object content;
            try {
                content = message.getContent();
                if (javax.mail.Multipart.class.isInstance(content)) {
                    System.out.println("CONTENT OBJECT CLASS: MULTIPART");
                    final javax.mail.Multipart multipart = (javax.mail.Multipart) content;
                    System.out.println("multipart content type: " + multipart.getContentType());
                    System.out.println("multipart count: " + multipart.getCount());
                    for (int i = 0; i < multipart.getCount(); i++) {
                        System.out.println("  multipart body[" + i + "]: " + multipart.getBodyPart(i));
                        BodyPart part = multipart.getBodyPart(i);
                        System.out.println("    content-type: " + part.getContentType());
                    }

                } else if (String.class.isInstance(content)) {
                    System.out.println("CONTENT IS A STRING: {" + content + "}");
                } else {
                    System.out.println("CONTENT OBJECT CLASS: " + content.getClass().toString());
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        store.close();

    }
}