Search in sources :

Example 56 with MimeBodyPart

use of javax.mail.internet.MimeBodyPart in project zm-mailbox by Zimbra.

the class ParseMimeMessage method parseMimeMsgSoap.

/**
     * Given an {@code <m>} element from SOAP, return us a parsed {@link MimeMessage}, and also fill in the
     * {@link MimeMessageData} structure with information we parsed out of it (e.g. contained Invite, msgids, etc etc)
     *
     * @param msgElem the {@code <m>} element
     * @param additionalParts MimeBodyParts that we want to have added to the {@link MimeMessage} (ie things the server
     * is adding onto the message)
     * @param inviteParser Callback which handles {@code <inv>} embedded invite components
     * @param out Holds info about things we parsed out of the message that the caller might want to know about
     */
public static MimeMessage parseMimeMsgSoap(ZimbraSoapContext zsc, OperationContext octxt, Mailbox mbox, Element msgElem, MimeBodyPart[] additionalParts, InviteParser inviteParser, MimeMessageData out, boolean attachMessageFromCache) throws ServiceException {
    // msgElem == "<m>" E_MSG
    assert (msgElem.getName().equals(MailConstants.E_MSG));
    Account target = DocumentHandler.getRequestedAccount(zsc);
    ParseMessageContext ctxt = new ParseMessageContext();
    ctxt.out = out;
    ctxt.zsc = zsc;
    ctxt.octxt = octxt;
    ctxt.mbox = mbox;
    ctxt.use2231 = target.isPrefUseRfc2231();
    ctxt.defaultCharset = target.getPrefMailDefaultCharset();
    if (Strings.isNullOrEmpty(ctxt.defaultCharset)) {
        ctxt.defaultCharset = MimeConstants.P_CHARSET_UTF8;
    }
    try {
        MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSmtpSession(target));
        MimeMultipart mmp = null;
        Element partElem = msgElem.getOptionalElement(MailConstants.E_MIMEPART);
        Element attachElem = msgElem.getOptionalElement(MailConstants.E_ATTACH);
        Element inviteElem = msgElem.getOptionalElement(MailConstants.E_INVITE);
        boolean hasContent = (partElem != null || inviteElem != null || additionalParts != null);
        // || inviteElem != null || additionalParts!=null);
        boolean isMultipart = (attachElem != null);
        if (isMultipart) {
            // may need to change to "digest" later
            mmp = new ZMimeMultipart("mixed");
            mm.setContent(mmp);
        }
        // Grab the <inv> part now so we can stick it in a multipart/alternative if necessary
        MimeBodyPart[] alternatives = null;
        if (inviteElem != null) {
            int additionalLen = 0;
            if (additionalParts != null) {
                additionalLen += additionalParts.length;
            }
            alternatives = new MimeBodyPart[additionalLen + 1];
            int curAltPart = 0;
            // goes into the "content" subpart
            InviteParserResult result = inviteParser.parse(zsc, octxt, mbox.getAccount(), inviteElem);
            if (partElem != null && result.mCal != null) {
                // If textual content is provided and there's an invite,
                // set the text as DESCRIPTION of the iCalendar.  This helps
                // clients that ignore alternative text content and only
                // displays the DESCRIPTION specified in the iCalendar part.
                // (e.g. MS Entourage for Mac)
                String desc = getTextPlainContent(partElem);
                String html = getTextHtmlContent(partElem);
                result.mCal.addDescription(desc, html);
                if (result.mInvite != null) {
                    // It's possible the notes were given in <inv> node only, with no corresponding MIME parts.
                    if ((desc != null && desc.length() > 0) || (html != null && html.length() > 0)) {
                        result.mInvite.setDescription(desc, html);
                        if (desc != null && desc.length() > 0) {
                            result.mInvite.setFragment(Fragment.getFragment(desc, true));
                        }
                    }
                }
            }
            MimeBodyPart mbp = CalendarMailSender.makeICalIntoMimePart(result.mCal);
            alternatives[curAltPart++] = mbp;
            if (additionalParts != null) {
                for (int i = 0; i < additionalParts.length; i++) {
                    alternatives[curAltPart++] = additionalParts[i];
                }
            }
        } else {
            alternatives = additionalParts;
        }
        // handle the content from the client, if any
        if (hasContent) {
            setContent(mm, mmp, partElem != null ? partElem : inviteElem, alternatives, ctxt);
        }
        // attachments go into the toplevel "mixed" part
        if (isMultipart && attachElem != null) {
            handleAttachments(attachElem, mmp, ctxt, null, Part.ATTACHMENT, attachMessageFromCache);
        }
        // <m> attributes: id, f[lags], s[ize], d[ate], cid(conv-id), l(parent folder)
        // <m> child elements: <e> (email), <s> (subject), <f> (fragment), <mp>, <attach>
        MessageAddresses maddrs = new MessageAddresses();
        Set<String> headerNames = ImmutableSet.copyOf(Provisioning.getInstance().getConfig().getCustomMimeHeaderNameAllowed());
        for (Element elem : msgElem.listElements()) {
            String eName = elem.getName();
            if (eName.equals(MailConstants.E_ATTACH)) {
            // ignore it...
            } else if (eName.equals(MailConstants.E_MIMEPART)) {
            /* <mp> */
            // processMessagePart(mm, elem);
            } else if (eName.equals(MailConstants.E_EMAIL)) {
                /* <e> */
                maddrs.add(elem, ctxt.defaultCharset);
            } else if (eName.equals(MailConstants.E_IN_REPLY_TO)) {
            /* <irt> */
            // mm.setHeader("In-Reply-To", elem.getText());
            } else if (eName.equals(MailConstants.E_SUBJECT)) {
            /* <su> */
            // mm.setSubject(elem.getText(), "utf-8");
            } else if (eName.equals(MailConstants.E_FRAG)) {
                /* <f> */
                ZimbraLog.soap.debug("Ignoring message fragment data");
            } else if (eName.equals(MailConstants.E_INVITE)) {
            /* <inv> */
            // Already processed above.  Ignore it.
            } else if (eName.equals(MailConstants.E_CAL_TZ)) {
            /* <tz> */
            // Ignore as a special case.
            } else if (eName.equals(MailConstants.E_HEADER)) {
                // <h>
                String name = elem.getAttribute(MailConstants.A_NAME);
                if (headerNames.contains(name)) {
                    mm.addHeader(name, MimeHeader.escape(elem.getText(), Charsets.UTF_8, true));
                } else {
                    throw ServiceException.INVALID_REQUEST("header '" + name + "' not allowed", null);
                }
            } else {
                ZimbraLog.soap.warn("unsupported child element '%s' under parent %s", elem.getName(), msgElem.getName());
            }
        }
        // deal with things that can be either <m> attributes or subelements
        String subject = msgElem.getAttribute(MailConstants.E_SUBJECT, "");
        mm.setSubject(subject, CharsetUtil.checkCharset(subject, ctxt.defaultCharset));
        String irt = cleanReference(msgElem.getAttribute(MailConstants.E_IN_REPLY_TO, null));
        if (irt != null) {
            mm.setHeader("In-Reply-To", irt);
        }
        // can have no addresses specified if it's a draft...
        if (!maddrs.isEmpty()) {
            addAddressHeaders(mm, maddrs);
        }
        if (!hasContent && !isMultipart) {
            mm.setText("", MimeConstants.P_CHARSET_DEFAULT);
        }
        String flagStr = msgElem.getAttribute(MailConstants.A_FLAGS, "");
        if (flagStr.indexOf(Flag.toChar(Flag.ID_HIGH_PRIORITY)) != -1) {
            mm.addHeader("X-Priority", "1");
            mm.addHeader("Importance", "high");
        } else if (flagStr.indexOf(Flag.toChar(Flag.ID_LOW_PRIORITY)) != -1) {
            mm.addHeader("X-Priority", "5");
            mm.addHeader("Importance", "low");
        }
        // JavaMail tip: don't forget to call this, it is REALLY confusing.
        mm.saveChanges();
        return mm;
    } catch (UnsupportedEncodingException e) {
        throw ServiceException.FAILURE("UnsupportedEncodingExecption", e);
    } catch (SendFailedException e) {
        SafeSendFailedException ssfe = new SafeSendFailedException(e);
        throw ServiceException.FAILURE("SendFailure", ssfe);
    } catch (MessagingException e) {
        throw ServiceException.FAILURE("MessagingExecption", e);
    } catch (IOException e) {
        throw ServiceException.FAILURE("IOExecption", e);
    }
}
Also used : Account(com.zimbra.cs.account.Account) SendFailedException(javax.mail.SendFailedException) SafeSendFailedException(com.zimbra.cs.mailbox.MailSender.SafeSendFailedException) MessagingException(javax.mail.MessagingException) Element(com.zimbra.common.soap.Element) UnsupportedEncodingException(java.io.UnsupportedEncodingException) SafeSendFailedException(com.zimbra.cs.mailbox.MailSender.SafeSendFailedException) IOException(java.io.IOException) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) ZMimeMessage(com.zimbra.common.zmime.ZMimeMessage) MimeMessage(javax.mail.internet.MimeMessage) ZMimeMultipart(com.zimbra.common.zmime.ZMimeMultipart) MimeMultipart(javax.mail.internet.MimeMultipart) ZMimeMultipart(com.zimbra.common.zmime.ZMimeMultipart) ZMimeBodyPart(com.zimbra.common.zmime.ZMimeBodyPart) MimeBodyPart(javax.mail.internet.MimeBodyPart)

Example 57 with MimeBodyPart

use of javax.mail.internet.MimeBodyPart in project zm-mailbox by Zimbra.

the class ParseMimeMessage method setContent.

/**
     * The <mp>'s from the client and the MimeBodyParts in alternatives[] all want to be "content"
     * of this MimeMessage.  The alternatives[] all need to be "alternative" to whatever the client sends
     * us....but we want to be careful so that we do NOT create a nested multipart/alternative structure
     * within another one (that would be very tacky)....so this is a bit complicated.
     */
private static void setContent(MimeMessage mm, MimeMultipart mmp, Element elem, MimeBodyPart[] alternatives, ParseMessageContext ctxt) throws MessagingException, ServiceException, IOException {
    String type = elem.getAttribute(MailConstants.A_CONTENT_TYPE, MimeConstants.CT_DEFAULT).trim();
    ContentType ctype = new ContentType(type, ctxt.use2231).cleanup();
    // is the client passing us a multipart?
    if (ctype.getPrimaryType().equals("multipart")) {
        // handle multipart content separately...
        setMultipartContent(ctype, mm, mmp, elem, alternatives, ctxt);
        return;
    }
    Element inline = elem.getOptionalElement(MailConstants.E_ATTACH);
    if (inline != null) {
        handleAttachments(inline, mmp, ctxt, elem.getAttribute(MailConstants.A_CONTENT_ID, null), Part.INLINE);
        return;
    }
    if (alternatives != null) {
        // create a multipart/alternative to hold all the alternatives
        MimeMultipart mmpNew = new ZMimeMultipart("alternative");
        if (mmp == null) {
            mm.setContent(mmpNew);
        } else {
            MimeBodyPart mbpWrapper = new ZMimeBodyPart();
            mbpWrapper.setContent(mmpNew);
            mmp.addBodyPart(mbpWrapper);
        }
        mmp = mmpNew;
    }
    // once we get here, mmp is either NULL, a multipart/mixed from the toplevel,
    // or a multipart/alternative created just above....either way we are safe to stick
    // the client's nice and simple body right here
    String text = elem.getAttribute(MailConstants.E_CONTENT, "");
    byte[] raw = text.getBytes(Charsets.UTF_8);
    if (raw.length > 0 || !LC.mime_exclude_empty_content.booleanValue() || ctype.getPrimaryType().equals("text")) {
        ctxt.incrementSize("message body", raw.length);
        // if the user has specified an alternative charset, make sure it exists and can encode the content
        String charset = CharsetUtil.checkCharset(text, ctxt.defaultCharset);
        ctype.setCharset(charset).setParameter(MimeConstants.P_CHARSET, charset);
        Object content = ctype.getContentType().equals(ContentType.MESSAGE_RFC822) ? new ZMimeMessage(JMSession.getSession(), new SharedByteArrayInputStream(raw)) : text;
        if (mmp != null) {
            MimeBodyPart mbp = new ZMimeBodyPart();
            mbp.setContent(content, ctype.toString());
            mmp.addBodyPart(mbp);
        } else {
            mm.setContent(content, ctype.toString());
        }
    }
    if (alternatives != null) {
        for (int i = 0; i < alternatives.length; i++) {
            ctxt.incrementSize("alternative body", alternatives[i].getSize());
            mmp.addBodyPart(alternatives[i]);
        }
    }
}
Also used : ZMimeMessage(com.zimbra.common.zmime.ZMimeMessage) ContentType(com.zimbra.common.mime.ContentType) ZMimeMultipart(com.zimbra.common.zmime.ZMimeMultipart) MimeMultipart(javax.mail.internet.MimeMultipart) ZMimeBodyPart(com.zimbra.common.zmime.ZMimeBodyPart) Element(com.zimbra.common.soap.Element) ZMimeMultipart(com.zimbra.common.zmime.ZMimeMultipart) ZMimeBodyPart(com.zimbra.common.zmime.ZMimeBodyPart) MimeBodyPart(javax.mail.internet.MimeBodyPart) Mountpoint(com.zimbra.cs.mailbox.Mountpoint) SharedByteArrayInputStream(javax.mail.util.SharedByteArrayInputStream)

Example 58 with MimeBodyPart

use of javax.mail.internet.MimeBodyPart in project zm-mailbox by Zimbra.

the class ParseMimeMessage method attachDocument.

private static void attachDocument(MimeMultipart mmp, Document doc, String contentID, ParseMessageContext ctxt) throws MessagingException, ServiceException {
    ctxt.incrementSize("attached document", (long) (doc.getSize() * 1.33));
    ContentType ct = new ContentType(doc.getContentType());
    if (MimeConstants.isZimbraDocument(ct.getContentType())) {
        ct = new ContentType(MimeConstants.CT_TEXT_HTML);
    }
    MimeBodyPart mbp = new ZMimeBodyPart();
    mbp.setDataHandler(new DataHandler(new MailboxBlobDataSource(doc.getBlob(), ct.getContentType())));
    mbp.setHeader("Content-Type", ct.cleanup().setParameter("name", doc.getName()).setCharset(ctxt.defaultCharset).toString());
    mbp.setHeader("Content-Disposition", new ContentDisposition(Part.ATTACHMENT).setParameter("filename", doc.getName()).toString());
    mbp.setContentID(contentID);
    mmp.addBodyPart(mbp);
}
Also used : ContentType(com.zimbra.common.mime.ContentType) ContentDisposition(com.zimbra.common.mime.ContentDisposition) ZMimeBodyPart(com.zimbra.common.zmime.ZMimeBodyPart) MailboxBlobDataSource(com.zimbra.cs.mime.MailboxBlobDataSource) DataHandler(javax.activation.DataHandler) ZMimeBodyPart(com.zimbra.common.zmime.ZMimeBodyPart) MimeBodyPart(javax.mail.internet.MimeBodyPart)

Example 59 with MimeBodyPart

use of javax.mail.internet.MimeBodyPart in project zm-mailbox by Zimbra.

the class ParseMimeMessage method attachContact.

private static void attachContact(MimeMultipart mmp, ItemId iid, String contentID, ParseMessageContext ctxt) throws MessagingException, ServiceException {
    if (!iid.isLocal()) {
        attachRemoteItem(mmp, iid, contentID, ctxt, FETCH_CONTACT_PARAMS, null);
        return;
    }
    Mailbox mbox = MailboxManager.getInstance().getMailboxByAccountId(iid.getAccountId());
    VCard vcf = VCard.formatContact(mbox.getContactById(ctxt.octxt, iid.getId()));
    ctxt.incrementSize("contact", vcf.getFormatted().length());
    String filename = vcf.fn + ".vcf";
    String charset = CharsetUtil.checkCharset(vcf.getFormatted(), ctxt.defaultCharset);
    MimeBodyPart mbp = new ZMimeBodyPart();
    mbp.setText(vcf.getFormatted(), charset);
    mbp.setHeader("Content-Type", new ContentType("text/x-vcard", ctxt.use2231).setCharset(ctxt.defaultCharset).setParameter("name", filename).setParameter("charset", charset).toString());
    mbp.setHeader("Content-Disposition", new ContentDisposition(Part.ATTACHMENT, ctxt.use2231).setCharset(ctxt.defaultCharset).setParameter("filename", filename).toString());
    mbp.setContentID(contentID);
    mmp.addBodyPart(mbp);
}
Also used : Mailbox(com.zimbra.cs.mailbox.Mailbox) ContentType(com.zimbra.common.mime.ContentType) ContentDisposition(com.zimbra.common.mime.ContentDisposition) ZMimeBodyPart(com.zimbra.common.zmime.ZMimeBodyPart) ZMimeBodyPart(com.zimbra.common.zmime.ZMimeBodyPart) MimeBodyPart(javax.mail.internet.MimeBodyPart) VCard(com.zimbra.cs.service.formatter.VCard)

Example 60 with MimeBodyPart

use of javax.mail.internet.MimeBodyPart in project zm-mailbox by Zimbra.

the class SendDeliveryReport method sendReport.

public static void sendReport(Account authAccount, Message msg, boolean automatic, String requestHost, String userAgent) throws ServiceException {
    MimeMessage mm = msg.getMimeMessage();
    Account owner = msg.getMailbox().getAccount();
    String charset = authAccount.getPrefMailDefaultCharset();
    if (charset == null) {
        charset = MimeConstants.P_CHARSET_UTF8;
    }
    try {
        InternetAddress[] recipients = Mime.parseAddressHeader(mm, "Disposition-Notification-To");
        if (recipients == null || recipients.length == 0)
            return;
        SMTPMessage report = new SMTPMessage(JMSession.getSmtpSession());
        String subject = "Read-Receipt: " + msg.getSubject();
        report.setSubject(subject, CharsetUtil.checkCharset(subject, charset));
        report.setSentDate(new Date());
        report.setFrom(AccountUtil.getFriendlyEmailAddress(authAccount));
        report.addRecipients(javax.mail.Message.RecipientType.TO, recipients);
        report.setHeader("Auto-Submitted", "auto-replied (zimbra; read-receipt)");
        report.setHeader("Precedence", "bulk");
        if (Provisioning.getInstance().getConfig().isAutoSubmittedNullReturnPath()) {
            report.setEnvelopeFrom("<>");
        } else {
            report.setEnvelopeFrom(authAccount.getName());
        }
        MimeMultipart multi = new ZMimeMultipart("report");
        // part 1: human-readable notification
        String text = generateTextPart(owner, mm, authAccount.getLocale());
        MimeBodyPart mpText = new ZMimeBodyPart();
        mpText.setText(text, CharsetUtil.checkCharset(text, charset));
        multi.addBodyPart(mpText);
        // part 2: disposition notification
        String mdn = generateReport(owner, mm, automatic, requestHost, userAgent);
        MimeBodyPart mpMDN = new ZMimeBodyPart();
        mpMDN.setText(mdn, MimeConstants.P_CHARSET_UTF8);
        mpMDN.setHeader("Content-Type", "message/disposition-notification; charset=utf-8");
        multi.addBodyPart(mpMDN);
        //            // part 3: original message
        //            MimeBodyPart mpOriginal = new ZMimeBodyPart();
        //            mpOriginal.setDataHandler(new DataHandler(new BlobDataSource(msg.getBlob())));
        //            mpOriginal.setHeader("Content-Type", MimeConstants.CT_MESSAGE_RFC822);
        //            mpOriginal.setHeader("Content-Disposition", Part.ATTACHMENT);
        //            multi.addBodyPart(mpOriginal);
        report.setContent(multi);
        report.setHeader("Content-Type", multi.getContentType() + "; report-type=disposition-notification");
        report.saveChanges();
        Transport.send(report);
    } catch (MessagingException me) {
        throw ServiceException.FAILURE("error while sending read receipt", me);
    }
}
Also used : Account(com.zimbra.cs.account.Account) InternetAddress(javax.mail.internet.InternetAddress) SMTPMessage(com.sun.mail.smtp.SMTPMessage) MimeMessage(javax.mail.internet.MimeMessage) ZMimeMultipart(com.zimbra.common.zmime.ZMimeMultipart) MimeMultipart(javax.mail.internet.MimeMultipart) ZMimeBodyPart(com.zimbra.common.zmime.ZMimeBodyPart) MessagingException(javax.mail.MessagingException) ZMimeMultipart(com.zimbra.common.zmime.ZMimeMultipart) ZMimeBodyPart(com.zimbra.common.zmime.ZMimeBodyPart) MimeBodyPart(javax.mail.internet.MimeBodyPart) Date(java.util.Date)

Aggregations

MimeBodyPart (javax.mail.internet.MimeBodyPart)172 MimeMultipart (javax.mail.internet.MimeMultipart)111 MimeMessage (javax.mail.internet.MimeMessage)65 MessagingException (javax.mail.MessagingException)64 IOException (java.io.IOException)49 DataHandler (javax.activation.DataHandler)39 ByteString (com.linkedin.data.ByteString)38 ByteArrayOutputStream (java.io.ByteArrayOutputStream)37 BodyPart (javax.mail.BodyPart)35 InternetAddress (javax.mail.internet.InternetAddress)31 ZMimeBodyPart (com.zimbra.common.zmime.ZMimeBodyPart)30 Test (org.testng.annotations.Test)28 ZMimeMultipart (com.zimbra.common.zmime.ZMimeMultipart)23 Multipart (javax.mail.Multipart)20 InputStream (java.io.InputStream)18 ArrayList (java.util.ArrayList)17 HashMap (java.util.HashMap)16 Session (javax.mail.Session)16 Date (java.util.Date)15 Properties (java.util.Properties)15