邮件多部分/替代与多部分/混合 [英] Mail multipart/alternative vs multipart/mixed

查看:26
本文介绍了邮件多部分/替代与多部分/混合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在创建电子邮件时,您应该设置Content-Typemultipart/alternative 发送 HTML 和 TEXT 或 multipart/mixed 发送文本和附件时.

When creating email messages you are supposed to set the Content-Type to multipart/alternative when sending HTML and TEXT or multipart/mixed when sending TEXT and attachments.

如果你想发送 HTML、文本和附件,你会怎么做?两个都用?

So what do you do if you want to send HTML, Text, and attachments? Use both?

推荐答案

我今天遇到了这个挑战,我发现这些答案很有用,但对我来说不够明确.

I hit this challenge today and I found these answers useful but not quite explicit enough for me.

编辑:刚刚找到Apache Commons Email这很好地概括了这一点,这意味着您无需在下面了解.

Edit: Just found the Apache Commons Email that wraps this up nicely, meaning you don't need to know below.

如果您的要求是带有以下内容的电子邮件:

If your requirement is an email with:

  1. 文本和 html 版本
  2. html 版本已嵌入(内嵌)图像
  3. 附件

我发现适用于 Gmail/Outlook/iPad 的唯一结构是:

The only structure I found that works with Gmail/Outlook/iPad is:

  • 混合
    • 替代方案
      • 文字
      • 相关
        • html
        • 内嵌图片
        • 内嵌图片

        代码是:

        import javax.activation.DataHandler;
        import javax.activation.DataSource;
        import javax.activation.URLDataSource;
        import javax.mail.BodyPart;
        import javax.mail.MessagingException;
        import javax.mail.Multipart;
        import javax.mail.internet.MimeBodyPart;
        import javax.mail.internet.MimeMultipart;
        import java.net.URL;
        import java.util.HashMap;
        import java.util.List;
        import java.util.UUID;
        import java.util.regex.Matcher;
        import java.util.regex.Pattern;
        
        /**
         * Created by StrongMan on 25/05/14.
         */
        public class MailContentBuilder {
        
            private static final Pattern COMPILED_PATTERN_SRC_URL_SINGLE = Pattern.compile("src='([^']*)'",  Pattern.CASE_INSENSITIVE);
            private static final Pattern COMPILED_PATTERN_SRC_URL_DOUBLE = Pattern.compile("src="([^"]*)"",  Pattern.CASE_INSENSITIVE);
        
            /**
             * Build an email message.
             *
             * The HTML may reference the embedded image (messageHtmlInline) using the filename. Any path portion is ignored to make my life easier
             * e.g. If you pass in the image C:Tempdog.jpg you can use <img src="dog.jpg"/> or <img src="C:Tempdog.jpg"/> and both will work
             *
             * @param messageText
             * @param messageHtml
             * @param messageHtmlInline
             * @param attachments
             * @return
             * @throws MessagingException
             */
            public Multipart build(String messageText, String messageHtml, List<URL> messageHtmlInline, List<URL> attachments) throws MessagingException {
                final Multipart mpMixed = new MimeMultipart("mixed");
                {
                    // alternative
                    final Multipart mpMixedAlternative = newChild(mpMixed, "alternative");
                    {
                        // Note: MUST RENDER HTML LAST otherwise iPad mail client only renders the last image and no email
                        addTextVersion(mpMixedAlternative,messageText);
                        addHtmlVersion(mpMixedAlternative,messageHtml, messageHtmlInline);
                    }
                    // attachments
                    addAttachments(mpMixed,attachments);
                }
        
                //msg.setText(message, "utf-8");
                //msg.setContent(message,"text/html; charset=utf-8");
                return mpMixed;
            }
        
            private Multipart newChild(Multipart parent, String alternative) throws MessagingException {
                MimeMultipart child =  new MimeMultipart(alternative);
                final MimeBodyPart mbp = new MimeBodyPart();
                parent.addBodyPart(mbp);
                mbp.setContent(child);
                return child;
            }
        
            private void addTextVersion(Multipart mpRelatedAlternative, String messageText) throws MessagingException {
                final MimeBodyPart textPart = new MimeBodyPart();
                textPart.setContent(messageText, "text/plain");
                mpRelatedAlternative.addBodyPart(textPart);
            }
        
            private void addHtmlVersion(Multipart parent, String messageHtml, List<URL> embeded) throws MessagingException {
                // HTML version
                final Multipart mpRelated = newChild(parent,"related");
        
                // Html
                final MimeBodyPart htmlPart = new MimeBodyPart();
                HashMap<String,String> cids = new HashMap<String, String>();
                htmlPart.setContent(replaceUrlWithCids(messageHtml,cids), "text/html");
                mpRelated.addBodyPart(htmlPart);
        
                // Inline images
                addImagesInline(mpRelated, embeded, cids);
            }
        
            private void addImagesInline(Multipart parent, List<URL> embeded, HashMap<String,String> cids) throws MessagingException {
                if (embeded != null)
                {
                    for (URL img : embeded)
                    {
                        final MimeBodyPart htmlPartImg = new MimeBodyPart();
                        DataSource htmlPartImgDs = new URLDataSource(img);
                        htmlPartImg.setDataHandler(new DataHandler(htmlPartImgDs));
                        String fileName = img.getFile();
                        fileName = getFileName(fileName);
                        String newFileName = cids.get(fileName);
                        boolean imageNotReferencedInHtml = newFileName == null;
                        if (imageNotReferencedInHtml) continue;
                        // Gmail requires the cid have <> around it
                        htmlPartImg.setHeader("Content-ID", "<"+newFileName+">");
                        htmlPartImg.setDisposition(BodyPart.INLINE);
                        parent.addBodyPart(htmlPartImg);
                    }
                }
            }
        
            private void addAttachments(Multipart parent, List<URL> attachments) throws MessagingException {
                if (attachments != null)
                {
                    for (URL attachment : attachments)
                    {
                        final MimeBodyPart mbpAttachment = new MimeBodyPart();
                        DataSource htmlPartImgDs = new URLDataSource(attachment);
                        mbpAttachment.setDataHandler(new DataHandler(htmlPartImgDs));
                        String fileName = attachment.getFile();
                        fileName = getFileName(fileName);
                        mbpAttachment.setDisposition(BodyPart.ATTACHMENT);
                        mbpAttachment.setFileName(fileName);
                        parent.addBodyPart(mbpAttachment);
                    }
                }
            }
        
            public String replaceUrlWithCids(String html, HashMap<String,String> cids)
            {
                html = replaceUrlWithCids(html, COMPILED_PATTERN_SRC_URL_SINGLE, "src='cid:@cid'", cids);
                html = replaceUrlWithCids(html, COMPILED_PATTERN_SRC_URL_DOUBLE, "src="cid:@cid"", cids);
                return html;
            }
        
            private String replaceUrlWithCids(String html, Pattern pattern, String replacement, HashMap<String,String> cids) {
                Matcher matcherCssUrl = pattern.matcher(html);
                StringBuffer sb = new StringBuffer();
                while (matcherCssUrl.find())
                {
                    String fileName = matcherCssUrl.group(1);
                    // Disregarding file path, so don't clash your filenames!
                    fileName = getFileName(fileName);
                    // A cid must start with @ and be globally unique
                    String cid = "@" + UUID.randomUUID().toString() + "_" + fileName;
                    if (cids.containsKey(fileName))
                        cid = cids.get(fileName);
                    else
                        cids.put(fileName,cid);
                    matcherCssUrl.appendReplacement(sb,replacement.replace("@cid",cid));
                }
                matcherCssUrl.appendTail(sb);
                html = sb.toString();
                return html;
            }
        
            private String getFileName(String fileName) {
                if (fileName.contains("/"))
                    fileName = fileName.substring(fileName.lastIndexOf("/")+1);
                return fileName;
            }
        }
        

        和一个从 Gmail 使用它的例子

        And an example of using it with from Gmail

        /**
         * Created by StrongMan on 25/05/14.
         */
        import com.sun.mail.smtp.SMTPTransport;
        
        import java.net.URL;
        import java.security.Security;
        import java.util.*;
        import java.util.regex.Matcher;
        import java.util.regex.Pattern;
        import javax.activation.DataHandler;
        import javax.activation.DataSource;
        import javax.activation.URLDataSource;
        import javax.mail.*;
        import javax.mail.internet.*;
        
        /**
         *
         * http://stackoverflow.com/questions/14744197/best-practices-sending-javamail-mime-multipart-emails-and-gmail
         * http://stackoverflow.com/questions/3902455/smtp-multipart-alternative-vs-multipart-mixed
         *
         *
         *
         * @author doraemon
         */
        public class GoogleMail {
        
        
            private GoogleMail() {
            }
        
            /**
             * Send email using GMail SMTP server.
             *
             * @param username GMail username
             * @param password GMail password
             * @param recipientEmail TO recipient
             * @param title title of the message
             * @param messageText message to be sent
             * @throws AddressException if the email address parse failed
             * @throws MessagingException if the connection is dead or not in the connected state or if the message is not a MimeMessage
             */
            public static void Send(final String username, final String password, String recipientEmail, String title, String messageText, String messageHtml, List<URL> messageHtmlInline, List<URL> attachments) throws AddressException, MessagingException {
                GoogleMail.Send(username, password, recipientEmail, "", title, messageText, messageHtml, messageHtmlInline,attachments);
            }
        
            /**
             * Send email using GMail SMTP server.
             *
             * @param username GMail username
             * @param password GMail password
             * @param recipientEmail TO recipient
             * @param ccEmail CC recipient. Can be empty if there is no CC recipient
             * @param title title of the message
             * @param messageText message to be sent
             * @throws AddressException if the email address parse failed
             * @throws MessagingException if the connection is dead or not in the connected state or if the message is not a MimeMessage
             */
            public static void Send(final String username, final String password, String recipientEmail, String ccEmail, String title, String messageText, String messageHtml, List<URL> messageHtmlInline, List<URL> attachments) throws AddressException, MessagingException {
                Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
                final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
        
                // Get a Properties object
                Properties props = System.getProperties();
                props.setProperty("mail.smtps.host", "smtp.gmail.com");
                props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
                props.setProperty("mail.smtp.socketFactory.fallback", "false");
                props.setProperty("mail.smtp.port", "465");
                props.setProperty("mail.smtp.socketFactory.port", "465");
                props.setProperty("mail.smtps.auth", "true");
        
                /*
                If set to false, the QUIT command is sent and the connection is immediately closed. If set
                to true (the default), causes the transport to wait for the response to the QUIT command.
        
                ref :   http://java.sun.com/products/javamail/javadocs/com/sun/mail/smtp/package-summary.html
                        http://forum.java.sun.com/thread.jspa?threadID=5205249
                        smtpsend.java - demo program from javamail
                */
                props.put("mail.smtps.quitwait", "false");
        
                Session session = Session.getInstance(props, null);
        
                // -- Create a new message --
                final MimeMessage msg = new MimeMessage(session);
        
                // -- Set the FROM and TO fields --
                msg.setFrom(new InternetAddress(username + "@gmail.com"));
                msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail, false));
        
                if (ccEmail.length() > 0) {
                    msg.setRecipients(Message.RecipientType.CC, InternetAddress.parse(ccEmail, false));
                }
        
                msg.setSubject(title);
        
                // mixed
                MailContentBuilder mailContentBuilder = new MailContentBuilder();
                final Multipart mpMixed = mailContentBuilder.build(messageText, messageHtml, messageHtmlInline, attachments);
                msg.setContent(mpMixed);
                msg.setSentDate(new Date());
        
                SMTPTransport t = (SMTPTransport)session.getTransport("smtps");
        
                t.connect("smtp.gmail.com", username, password);
                t.sendMessage(msg, msg.getAllRecipients());
                t.close();
            }
        
        }
        

        这篇关于邮件多部分/替代与多部分/混合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆