immf.SendMailBridge.java Source code

Java tutorial

Introduction

Here is the source code for immf.SendMailBridge.java

Source

/*
 * imoten - i mode.net mail tensou(forward)
 *
 * Copyright (C) 2010 shoozhoo (http://code.google.com/p/imoten/)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 */

package immf;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.internet.AddressException;
import javax.mail.internet.ContentType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.subethamail.smtp.auth.LoginFailedException;
import org.subethamail.smtp.auth.UsernamePasswordValidator;

public class SendMailBridge implements UsernamePasswordValidator, MyWiserMailListener {
    private static final int MaxRecipient = 5;
    private static final Log log = LogFactory.getLog(SendMailBridge.class);

    private ImodeNetClient client;
    private SendMailPicker picker;
    private StatusManager status;

    private String user;
    private String passwd;
    private String alwaysBcc;
    private boolean forcePlainText;
    private boolean isForwardSent;
    private boolean stripAppleQuote;
    private boolean editDocomoSubjectPrefix;

    private MyWiser wiser;
    private CharacterConverter charConv;
    private CharacterConverter googleCharConv;
    private boolean useGoomojiSubject;
    private int duplicationCheckTimeSec;
    private boolean sendAsync;

    private Map<String, List<String>> receivedMessageTable;

    public SendMailBridge(Config conf, ImodeNetClient client, SendMailPicker picker, StatusManager status) {
        if (conf.getSenderSmtpPort() <= 0) {
            return;
        }
        this.client = client;
        this.picker = picker;
        this.status = status;
        this.user = conf.getSenderUser();
        this.passwd = conf.getSenderPasswd();
        this.alwaysBcc = conf.getSenderAlwaysBcc();
        this.forcePlainText = conf.isSenderMailForcePlainText();
        this.isForwardSent = conf.isForwardSent();
        this.stripAppleQuote = conf.isSenderStripiPhoneQuote();
        this.editDocomoSubjectPrefix = conf.isSenderDocomoStyleSubject();
        this.sendAsync = conf.isSenderAsync();
        this.charConv = new CharacterConverter();
        for (String file : conf.getSenderCharCovertFile()) {
            try {
                this.charConv.load(new File(file));
            } catch (Exception e) {
                log.error("?(" + file + ")????????", e);
            }
        }
        this.charConv.setConvertSoftbankSjis(conf.isSenderConvertSoftbankSjis());
        this.googleCharConv = new CharacterConverter();
        if (conf.getSenderGoogleCharConvertFile() != null) {
            try {
                this.googleCharConv.load(new File(conf.getSenderGoogleCharConvertFile()));
            } catch (Exception e) {
                log.error("?(" + conf.getSenderGoogleCharConvertFile()
                        + ")????????", e);
            }
        }
        this.useGoomojiSubject = conf.isSenderUseGoomojiSubject();

        this.duplicationCheckTimeSec = conf.getSenderDuplicationCheckTimeSec();
        if (this.duplicationCheckTimeSec > 0)
            this.receivedMessageTable = new HashMap<String, List<String>>();
        else
            this.receivedMessageTable = null;

        log.info("SMTP????");
        this.wiser = new MyWiser(this, conf.getSenderSmtpPort(), this, conf.getSenderTlsKeystore(),
                conf.getSenderTlsKeyType(), conf.getSenderTlsKeyPasswd());
        this.wiser.start();

    }

    /**
     * SMTP???????
     * @param msg
     * @throws IOException
     */
    public void receiveMail(MyWiserMessage msg) throws IOException {
        try {
            SenderMail senderMail = new SenderMail();

            log.info("==== SMTP???????====");
            log.info("From       " + msg.getEnvelopeSender());
            log.info("Recipients  " + msg.getEnvelopeReceiver());

            MimeMessage mime = msg.getMimeMessage();

            String messageId = mime.getHeader("Message-ID", null);
            log.info("messageID  " + messageId);
            List<String> recipients;
            if (messageId != null && receivedMessageTable != null) {
                synchronized (receivedMessageTable) {
                    recipients = receivedMessageTable.get(messageId);
                    if (recipients != null) {
                        recipients.addAll(msg.getEnvelopeReceiver());
                        log.info("Duplicated message ignored");
                        return;
                    }

                    recipients = msg.getEnvelopeReceiver();
                    receivedMessageTable.put(messageId, recipients);
                    receivedMessageTable.wait(this.duplicationCheckTimeSec * 1000);
                    receivedMessageTable.remove(messageId);
                }
            } else {
                recipients = msg.getEnvelopeReceiver();
            }

            List<InternetAddress> to = getRecipients(mime, "To");
            List<InternetAddress> cc = getRecipients(mime, "Cc");
            List<InternetAddress> bcc = getBccRecipients(recipients, to, cc);

            int maxRecipients = MaxRecipient;
            if (this.alwaysBcc != null) {
                log.debug("add alwaysbcc " + this.alwaysBcc);
                bcc.add(new InternetAddress(this.alwaysBcc));
            }
            log.info("To   " + StringUtils.join(to, " / "));
            log.info("cc   " + StringUtils.join(cc, " / "));
            log.info("bcc   " + StringUtils.join(bcc, " / "));

            senderMail.setTo(to);
            senderMail.setCc(cc);
            senderMail.setBcc(bcc);

            if (maxRecipients < (to.size() + cc.size() + bcc.size())) {
                log.warn("??????i.net???5??");
                throw new IOException("Too Much Recipients");
            }

            String contentType = mime.getContentType().toLowerCase();
            log.info("ContentType:" + contentType);

            String charset = (new ContentType(contentType)).getParameter("charset");
            log.info("charset:" + charset);

            String mailer = mime.getHeader("X-Mailer", null);
            log.info("mailer  " + mailer);

            String subject = mime.getHeader("Subject", null);
            log.info("subject  " + subject);
            if (subject != null)
                subject = this.charConv.convertSubject(subject);
            log.debug(" conv " + subject);

            if (this.useGoomojiSubject) {
                String goomojiSubject = mime.getHeader("X-Goomoji-Subject", null);
                if (goomojiSubject != null)
                    subject = this.googleCharConv.convertSubject(goomojiSubject);
            }

            boolean editRe = false;
            if (this.editDocomoSubjectPrefix) {
                for (InternetAddress addr : to) {
                    String[] toString = addr.getAddress().split("@", 2);
                    if (subject != null && toString[1].equals("docomo.ne.jp")) {
                        editRe = true;
                    }
                }
            }
            if (editRe) {
                if (subject.matches("^R[eE]: ?R[eE].*$")) {
                    log.info("?subject: " + subject);
                    String reCounterStr = subject.replaceAll("^R[eE]: ?R[eE](\\d*):.*$", "$1");
                    int reCounter = 2;
                    if (!reCounterStr.isEmpty()) {
                        reCounter = Integer.parseInt(reCounterStr);
                        reCounter++;
                    }
                    subject = subject.replaceAll("^R[eE]: ?R[eE]\\d*:", "Re" + Integer.toString(reCounter) + ":");
                    log.info("subject: " + subject);
                }
            }

            senderMail.setSubject(subject);

            Object content = mime.getContent();
            if (content instanceof String) {
                // 
                String strContent = (String) content;
                if (contentType.toLowerCase().startsWith("text/html")) {
                    log.info("Single html part " + strContent);
                    strContent = this.charConv.convert(strContent, charset);
                    log.debug(" conv " + strContent);
                    senderMail.setHtmlContent(strContent);
                } else {
                    log.info("Single plainText part " + strContent);
                    strContent = this.charConv.convert(strContent, charset);
                    log.debug(" conv " + strContent);
                    senderMail.setPlainTextContent(strContent);
                }
            } else if (content instanceof Multipart) {
                Multipart mp = (Multipart) content;
                parseMultipart(senderMail, mp, getSubtype(contentType), null);
                if (senderMail.getHtmlContent() == null && senderMail.getHtmlWorkingContent() != null) {
                    senderMail.setHtmlContent(senderMail.getHtmlWorkingContent());
                }

            } else {
                log.warn("? " + content.getClass().getName());
                throw new IOException("Unsupported type " + content.getClass().getName() + ".");
            }

            if (stripAppleQuote) {
                Util.stripAppleQuotedLines(senderMail);
            }
            Util.stripLastEmptyLines(senderMail);

            log.info("Content  " + mime.getContent());
            log.info("====");

            if (this.sendAsync) {
                // ??
                // ?????OK?
                this.picker.add(senderMail);
            } else {
                // ??????
                this.client.sendMail(senderMail, this.forcePlainText);
                if (isForwardSent) {
                    status.setNeedConnect();
                }
            }

        } catch (IOException e) {
            log.warn("Bad Mail Received.", e);
            throw e;
        } catch (Exception e) {
            log.error("ReceiveMail Error.", e);
            throw new IOException("ReceiveMail Error." + e.getMessage(), e);
        }
    }

    /*
     * ??
     */
    private void parseMultipart(SenderMail sendMail, Multipart mp, String subtype, String parentSubtype)
            throws IOException {
        String contentType = mp.getContentType();
        log.info("Multipart ContentType:" + contentType);

        try {
            int count = mp.getCount();
            log.info("count " + count);

            boolean hasInlinePart = false;
            if (subtype.equalsIgnoreCase("mixed")) {
                for (int i = 0; i < count; i++) {
                    String d = mp.getBodyPart(i).getDisposition();
                    if (d != null && d.equalsIgnoreCase(Part.INLINE))
                        hasInlinePart = true;
                }
            }
            if (hasInlinePart) {
                log.info("parseBodypart(Content-Disposition:inline)");
                for (int i = 0; i < count; i++) {
                    parseBodypartmixed(sendMail, mp.getBodyPart(i), subtype, parentSubtype);
                }
                if (sendMail.getHtmlContent() != null) {
                    sendMail.addHtmlContent("</body>");
                }
                if (sendMail.getHtmlWorkingContent() != null) {
                    sendMail.addHtmlWorkingContent("</body>");
                }
            } else {
                for (int i = 0; i < count; i++) {
                    parseBodypart(sendMail, mp.getBodyPart(i), subtype, parentSubtype);
                }
            }
        } catch (Exception e) {
            log.error("parse multipart error.", e);
            //throw new IOException("MimeMultiPart error."+e.getMessage(),e);
        }
    }

    private static String getSubtype(String contenttype) {
        try {
            String r = contenttype.split("\\r?\\n")[0];
            return r.split("/")[1].replaceAll("\\s*;.*", "");
        } catch (Exception e) {
        }
        return "";
    }

    private static String getBasename(String filename) {
        try {
            int dot = filename.lastIndexOf(".");
            if (dot > 0) {
                return filename.substring(0, dot);
            } else {
                return filename;
            }
        } catch (Exception e) {
        }
        return filename;
    }

    /*
     * ???(multipart/alternative)
     */
    private void parseBodypart(SenderMail sendMail, BodyPart bp, String subtype, String parentSubtype)
            throws IOException {
        boolean limiterr = false;
        String badfile = null;
        try {
            String contentType = bp.getContentType().toLowerCase();
            log.info("Bodypart ContentType:" + contentType);
            log.info("subtype:" + subtype);

            if (contentType.startsWith("multipart/")) {
                parseMultipart(sendMail, (Multipart) bp.getContent(), getSubtype(contentType), subtype);

            } else if (sendMail.getPlainTextContent() == null && contentType.startsWith("text/plain")) {
                // ???plain/text?
                String content = (String) bp.getContent();
                log.info("set Content text [" + content + "]");
                String charset = (new ContentType(contentType)).getParameter("charset");
                content = this.charConv.convert(content, charset);
                log.debug(" conv " + content);
                sendMail.setPlainTextContent(content);

            } else if (sendMail.getHtmlContent() == null && contentType.startsWith("text/html")
                    && (subtype.equalsIgnoreCase("alternative") || subtype.equalsIgnoreCase("related"))) {
                String content = (String) bp.getContent();
                log.info("set Content html [" + content + "]");
                String charset = (new ContentType(contentType)).getParameter("charset");
                content = this.charConv.convert(content, charset);
                log.debug(" conv " + content);
                //  html????
                sendMail.setHtmlContent(content);

            } else if (contentType.startsWith("text/html")) {
                // subtype?mixed??
                String content = (String) bp.getContent();

                if (sendMail.getHtmlContent() == null) {
                    // text/plain???????? text/html?????????
                    log.info("set Content html [" + content + "]");
                    String charset = (new ContentType(contentType)).getParameter("charset");
                    content = this.charConv.convert(content, charset);
                    log.debug(" conv " + content);
                    //  html????
                    sendMail.setHtmlContent(content);
                } else {
                    log.info("Discarding duplicate content [" + content + "]");
                }

            } else {
                log.debug("attach");
                // ????

                if (subtype.equalsIgnoreCase("related")) {
                    // 
                    SenderAttachment file = new SenderAttachment();
                    String fname = uniqId();
                    String fname2 = Util.getFileName(bp);

                    // iPhone?gifpng?????????????ContentType(?png???gif?)
                    if (getSubtype(contentType).equalsIgnoreCase("png")) {
                        file.setContentType("image/gif");
                        fname = fname + ".gif";
                        fname2 = getBasename(fname2) + ".gif";
                        file.setData(inputstream2bytes(Util.png2gif(bp.getInputStream())));
                    } else {
                        file.setContentType(contentType);
                        fname = fname + "." + getSubtype(contentType);
                        file.setData(inputstream2bytes(bp.getInputStream()));
                    }

                    file.setInline(true);
                    boolean inline = !this.forcePlainText & sendMail.checkAttachmentCapability(file);
                    if (!inline) {
                        file.setInline(false);
                        if (!sendMail.checkAttachmentCapability(file)) {
                            limiterr = true;
                            badfile = fname2;
                            throw new Exception("Attachments: size limit or file count limit exceeds!");
                        }
                    }

                    if (inline) {
                        file.setFilename(fname);
                        file.setContentId(bp.getHeader("Content-Id")[0]);
                        log.info("Inline Attachment " + file.loggingString() + ", Hash:" + file.getHash());
                    } else {
                        file.setFilename(fname2);
                        log.info("Attachment " + file.loggingString());
                    }
                    sendMail.addAttachmentFileIdList(file);

                } else {
                    // ?
                    SenderAttachment file = new SenderAttachment();
                    file.setInline(false);
                    file.setContentType(contentType);
                    String fname = Util.getFileName(bp);
                    if (getSubtype(contentType).equalsIgnoreCase("png")) {
                        file.setContentType("image/gif");
                        file.setFilename(getBasename(fname) + ".gif");
                        file.setData(inputstream2bytes(Util.png2gif(bp.getInputStream())));
                    } else {
                        file.setFilename(fname);
                        file.setData(inputstream2bytes(bp.getInputStream()));
                    }
                    if (!sendMail.checkAttachmentCapability(file)) {
                        limiterr = true;
                        badfile = file.getFilename();
                        throw new Exception("Attachments: size limit or file count limit exceeds!");
                    }
                    sendMail.addAttachmentFileIdList(file);
                    log.info("Attachment " + file.loggingString());
                }
            }
        } catch (Exception e) {
            log.error("parse bodypart error.", e);
            if (limiterr) {
                sendMail.addPlainTextContent("\n[(" + badfile + ")]");
                if (sendMail.getHtmlContent() != null) {
                    sendMail.addHtmlContent("[(" + badfile + ")]<br>");
                }
            } else {
                throw new IOException("BodyPart error." + e.getMessage(), e);
            }
        }
    }

    /*
     * ???(multipart/mixed)
     * (Content-Disposition????????)
     */
    private void parseBodypartmixed(SenderMail sendMail, BodyPart bp, String subtype, String parentSubtype)
            throws IOException {
        boolean limiterr = false;
        String badfile = null;
        try {
            String contentType = bp.getContentType().toLowerCase();
            log.info("Bodypart ContentType:" + contentType);
            log.info("subtype:" + subtype);

            if (contentType.startsWith("multipart/")) {
                parseMultipart(sendMail, (Multipart) bp.getContent(), getSubtype(contentType), subtype);

            } else if (sendMail.getPlainTextContent() == null && contentType.startsWith("text/plain")) {
                // ???plain/text?
                String content = (String) bp.getContent();
                log.info("set Content text [" + content + "]");
                String charset = (new ContentType(contentType)).getParameter("charset");
                content = this.charConv.convert(content, charset);
                log.debug(" conv " + content);
                sendMail.setPlainTextContent(content);

                // HTML??????<br>????????HtmlConverter?
                // ??????HTML???HTML???????
                if (sendMail.getHtmlWorkingContent() == null) {
                    sendMail.setHtmlWorkingContent(
                            "<body>" + Util.easyEscapeHtml(content).replaceAll("\\r\\n", "<br>") + "<br>");
                } else {
                    sendMail.addHtmlWorkingContent(
                            Util.easyEscapeHtml(content).replaceAll("\\r\\n", "<br>") + "<br>");
                }

            } else if (sendMail.getHtmlContent() == null && contentType.startsWith("text/html")
                    && (parentSubtype.equalsIgnoreCase("alternative")
                            || parentSubtype.equalsIgnoreCase("related"))) {
                // ???text/html
                String content = (String) bp.getContent();
                log.info("set Content html [" + content + "]");
                String charset = (new ContentType(contentType)).getParameter("charset");
                // 2?3?HTML?????????</body>???????
                content = this.charConv.convert(content, charset);
                content = HtmlConvert.replaceAllCaseInsenstive(content, "</body>.*", "");
                log.debug(" conv " + content);
                sendMail.setHtmlContent(content);

            } else {
                log.debug("attach");
                // ????

                String contentDisposition = bp.getDisposition();
                if (contentDisposition != null && contentDisposition.equalsIgnoreCase(Part.INLINE)) {
                    // 
                    SenderAttachment file = new SenderAttachment();
                    String uniqId = uniqId();
                    String fname = uniqId;
                    String fname2 = Util.getFileName(bp);

                    // iPhone?gifpng?????????????gif??(?png???gif?)
                    if (getSubtype(contentType).equalsIgnoreCase("png")) {
                        file.setContentType("image/gif");
                        fname = fname + ".gif";
                        fname2 = getBasename(fname2) + ".gif";
                        file.setData(inputstream2bytes(Util.png2gif(bp.getInputStream())));
                    } else {
                        file.setContentType(contentType);
                        fname = fname + "." + getSubtype(contentType);
                        file.setData(inputstream2bytes(bp.getInputStream()));
                    }

                    file.setInline(true);
                    boolean inline = !this.forcePlainText & sendMail.checkAttachmentCapability(file);
                    if (!inline) {
                        file.setInline(false);
                        if (!sendMail.checkAttachmentCapability(file)) {
                            limiterr = true;
                            badfile = fname2;
                            throw new Exception("Attachments: size limit or file count limit exceeds!");
                        }
                    }

                    if (inline) {
                        file.setFilename(fname);
                        if (bp.getHeader("Content-Id") == null) {
                            file.setContentId(uniqId);
                        } else {
                            file.setContentId(bp.getHeader("Content-Id")[0]);
                        }
                        log.info("Inline Attachment(mixed) " + file.loggingString() + ", Hash:" + file.getHash());

                        // ??HTML?
                        if (sendMail.getHtmlContent() != null) {
                            sendMail.addHtmlContent("<img src=\"cid:" + file.getContentId() + "\"><br>");
                        }
                        if (sendMail.getHtmlWorkingContent() == null) {
                            sendMail.setHtmlWorkingContent(
                                    "<body><img src=\"cid:" + file.getContentId() + "\"><br>");
                        } else {
                            sendMail.addHtmlWorkingContent("<img src=\"cid:" + file.getContentId() + "\"><br>");
                        }
                    } else {
                        file.setFilename(fname2);
                        log.info("Attachment " + file.loggingString());
                    }
                    sendMail.addAttachmentFileIdList(file);

                } else {
                    // ?
                    SenderAttachment file = new SenderAttachment();
                    file.setInline(false);
                    file.setContentType(contentType);
                    String fname = Util.getFileName(bp);
                    if (fname == null && sendMail.getPlainTextContent() != null
                            && contentType.startsWith("text/plain")) {
                        // ???????
                        String content = (String) bp.getContent();
                        log.info("add Content text [" + content + "]");
                        String charset = (new ContentType(contentType)).getParameter("charset");
                        content = this.charConv.convert(content, charset);
                        log.debug(" conv " + content);

                        // ??HTML????<br>
                        sendMail.addPlainTextContent("\n" + content);
                        sendMail.addHtmlWorkingContent(
                                Util.easyEscapeHtml(content).replaceAll("\\r\\n", "<br>") + "<br>");

                    } else if (fname == null && sendMail.getHtmlContent() != null
                            && contentType.startsWith("text/html") && (parentSubtype.equalsIgnoreCase("alternative")
                                    || parentSubtype.equalsIgnoreCase("related"))) {
                        // ????text/html????
                        String content = (String) bp.getContent();
                        log.info("add Content html [" + content + "]");
                        String charset = (new ContentType(contentType)).getParameter("charset");
                        content = this.charConv.convert(content, charset);
                        content = HtmlConvert.replaceAllCaseInsenstive(content, ".*<body[^>]*>", "");
                        content = HtmlConvert.replaceAllCaseInsenstive(content, "</body>.*", "");
                        log.debug(" conv " + content);
                        sendMail.addHtmlContent(content);

                    } else {
                        // ??????
                        if (getSubtype(contentType).equalsIgnoreCase("png")) {
                            file.setContentType("image/gif");
                            file.setFilename(getBasename(fname) + ".gif");
                            file.setData(inputstream2bytes(Util.png2gif(bp.getInputStream())));
                        } else {
                            file.setFilename(fname);
                            file.setData(inputstream2bytes(bp.getInputStream()));
                        }
                        if (!sendMail.checkAttachmentCapability(file)) {
                            limiterr = true;
                            badfile = file.getFilename();
                            throw new Exception("Attachments: size limit or file count limit exceeds!");
                        }
                        sendMail.addAttachmentFileIdList(file);
                        log.info("Attachment " + file.loggingString());

                    }
                }
            }
        } catch (Exception e) {
            log.error("parse bodypart error(mixed).", e);
            if (limiterr) {
                sendMail.addPlainTextContent("\n[(" + badfile + ")]");
                if (sendMail.getHtmlContent() != null) {
                    sendMail.addHtmlContent("[(" + badfile + ")]<br>");
                }
                if (sendMail.getHtmlWorkingContent() == null) {
                    sendMail.setHtmlWorkingContent("<body>[(" + badfile + ")]<br>");
                } else {
                    sendMail.addHtmlWorkingContent("[(" + badfile + ")]<br>");
                }
            } else {
                throw new IOException("BodyPart error(mixed)." + e.getMessage(), e);
            }
        }
    }

    private static int fileNameId = 0;

    private static String uniqId() {
        fileNameId++;
        return System.currentTimeMillis() + "_" + fileNameId;
    }

    private static byte[] inputstream2bytes(InputStream is) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            byte[] buf = new byte[1024 * 4];
            while (true) {
                int len = is.read(buf);
                if (len <= 0) {
                    break;
                }
                bos.write(buf, 0, len);
            }
        } finally {
            try {
                is.close();
            } catch (Exception e) {
            }
            try {
                bos.close();
            } catch (Exception e) {
            }
        }
        return bos.toByteArray();
    }

    private static List<InternetAddress> getBccRecipients(List<String> allRecipients, List<InternetAddress> to,
            List<InternetAddress> cc) throws AddressException {
        List<String> addrList = new ArrayList<String>();
        List<String> toccAddrList = new ArrayList<String>();
        for (String addr : allRecipients) {
            addrList.add(addr);
        }
        for (InternetAddress ia : to) {
            toccAddrList.add(ia.getAddress());
        }
        for (InternetAddress ia : cc) {
            toccAddrList.add(ia.getAddress());
        }
        addrList.removeAll(toccAddrList);
        List<InternetAddress> r = new ArrayList<InternetAddress>();
        for (String addr : addrList) {
            r.add(new InternetAddress(addr));
        }
        return r;
    }

    private static List<InternetAddress> getRecipients(MimeMessage msg, String type) throws MessagingException {
        List<InternetAddress> r = new ArrayList<InternetAddress>();
        String[] headers = msg.getHeader(type);
        if (headers == null) {
            return r;
        }
        for (String h : headers) {
            InternetAddress[] addrs = InternetAddress.parse(h);
            CollectionUtils.addAll(r, addrs);
        }
        return r;
    }

    public void login(String user, String pass) throws LoginFailedException {
        log.debug("* SMTP Login *");
        if (!StringUtils.equals(this.user, user) || !StringUtils.equals(this.passwd, pass)) {
            log.warn("SMTP ? User " + user + "/ Pass " + pass);
            throw new LoginFailedException("SMTP Auth Login Error.");
        }
    }

}