public static ByteArrayOutputStream getPayload(MultipartPayload multipartPayload) throws IOException {
        final ByteArrayOutputStream os = new ByteArrayOutputStream();

        final String preamble = multipartPayload.getPreamble();
        if (preamble != null) {
            os.write((preamble + "\r\n").getBytes());
        }
        final List<BodyPartPayload> bodyParts = multipartPayload.getBodyParts();
        if (!bodyParts.isEmpty()) {
            final String boundary = multipartPayload.getBoundary();
            final byte[] startBoundary = ("--" + boundary + "\r\n").getBytes();

            for (BodyPartPayload bodyPart : bodyParts) {
                os.write(startBoundary);

                final Map<String, String> bodyPartHeaders = bodyPart.getHeaders();
                if (bodyPartHeaders != null) {
                    for (Map.Entry<String, String> header : bodyPartHeaders.entrySet()) {
                        os.write((header.getKey() + ": " + header.getValue() + "\r\n").getBytes());
                    }
                }

                os.write("\r\n".getBytes());
                if (bodyPart instanceof MultipartPayload) {
                    getPayload((MultipartPayload) bodyPart).writeTo(os);
                } else if (bodyPart instanceof ByteArrayBodyPartPayload) {
                    final ByteArrayBodyPartPayload byteArrayBodyPart = (ByteArrayBodyPartPayload) bodyPart;
                    os.write(byteArrayBodyPart.getPayload(), byteArrayBodyPart.getOff(), byteArrayBodyPart.getLen());
                } else {
                    throw new AssertionError(bodyPart.getClass());
                }
                os.write("\r\n".getBytes()); //CRLF for the next (starting or closing) boundary
            }

            os.write(("--" + boundary + "--").getBytes());
            final String epilogue = multipartPayload.getEpilogue();
            if (epilogue != null) {
                os.write(("\r\n" + epilogue).getBytes());
            }

        }
        return os;
    }
@Test
    public void testComplexMultipartPayload() throws IOException {
        final MultipartPayload mP = new MultipartPayload("mixed", "unique-boundary-1");

        mP.setPreamble("This is the preamble area of a multipart message.\n"
                + "Mail readers that understand multipart format\n"
                + "should ignore this preamble.\n"
                + "\n"
                + "If you are reading this text, you might want to\n"
                + "consider changing to a mail reader that understands\n"
                + "how to properly display multipart messages.\n");

        mP.addBodyPart(new ByteArrayBodyPartPayload("... Some text appears here ...".getBytes()));

        mP.addBodyPart(new ByteArrayBodyPartPayload(("This could have been part of the previous part, but\n"
                + "illustrates explicit versus implicit typing of body\n"
                + "parts.\n").getBytes(), "text/plain; charset=US-ASCII"));

        final MultipartPayload innerMP = new MultipartPayload("parallel", "unique-boundary-2");
        mP.addBodyPart(innerMP);

        final Map<String, String> audioHeaders = new LinkedHashMap<>();
        audioHeaders.put("Content-Type", "audio/basic");
        audioHeaders.put("Content-Transfer-Encoding", "base64");
        innerMP.addBodyPart(new ByteArrayBodyPartPayload(("... base64-encoded 8000 Hz single-channel\n"
                + "    mu-law-format audio data goes here ...").getBytes(), audioHeaders));

        final Map<String, String> imageHeaders = new LinkedHashMap<>();
        imageHeaders.put("Content-Type", "image/jpeg");
        imageHeaders.put("Content-Transfer-Encoding", "base64");
        innerMP.addBodyPart(new ByteArrayBodyPartPayload("... base64-encoded image data goes here ...".getBytes(),
                imageHeaders));

        mP.addBodyPart(new ByteArrayBodyPartPayload(("This is <bold><italic>enriched.</italic></bold>\n"
                + "<smaller>as defined in RFC 1896</smaller>\n"
                + "\n"
                + "Isn't it\n"
                + "<bigger><bigger>cool?</bigger></bigger>\n").getBytes(), "text/enriched"));

        mP.addBodyPart(new ByteArrayBodyPartPayload(("From: (mailbox in US-ASCII)\n"
                + "To: (address in US-ASCII)\n"
                + "Subject: (subject in US-ASCII)\n"
                + "Content-Type: Text/plain; charset=ISO-8859-1\n"
                + "Content-Transfer-Encoding: Quoted-printable\n"
                + "\n"
                + "... Additional text in ISO-8859-1 goes here ...\n").getBytes(), "message/rfc822"));

        final StringBuilder headersString = new StringBuilder();
        for (Map.Entry<String, String> header : mP.getHeaders().entrySet()) {
            headersString.append(header.getKey())
                    .append(": ")
                    .append(header.getValue())
                    .append("\r\n");
        }
        assertEquals("Content-Type: multipart/mixed; boundary=\"unique-boundary-1\"\r\n", headersString.toString());

        assertEquals("This is the preamble area of a multipart message.\n"
                + "Mail readers that understand multipart format\n"
                + "should ignore this preamble.\n"
                + "\n"
                + "If you are reading this text, you might want to\n"
                + "consider changing to a mail reader that understands\n"
                + "how to properly display multipart messages.\n"
                + "\r\n--unique-boundary-1\r\n"
                + "\r\n"
                + "... Some text appears here ..."
                + "\r\n--unique-boundary-1\r\n"
                + "Content-Type: text/plain; charset=US-ASCII\r\n"
                + "\r\n"
                + "This could have been part of the previous part, but\n"
                + "illustrates explicit versus implicit typing of body\n"
                + "parts.\n"
                + "\r\n--unique-boundary-1\r\n"
                + "Content-Type: multipart/parallel; boundary=\"unique-boundary-2\"\r\n"
                + "\r\n--unique-boundary-2\r\n"
                + "Content-Type: audio/basic\r\n"
                + "Content-Transfer-Encoding: base64\r\n"
                + "\r\n"
                + "... base64-encoded 8000 Hz single-channel\n"
                + "    mu-law-format audio data goes here ..."
                + "\r\n--unique-boundary-2\r\n"
                + "Content-Type: image/jpeg\r\n"
                + "Content-Transfer-Encoding: base64\r\n"
                + "\r\n"
                + "... base64-encoded image data goes here ..."
                + "\r\n--unique-boundary-2--"
                + "\r\n--unique-boundary-1\r\n"
                + "Content-Type: text/enriched\r\n"
                + "\r\n"
                + "This is <bold><italic>enriched.</italic></bold>\n"
                + "<smaller>as defined in RFC 1896</smaller>\n"
                + "\n"
                + "Isn't it\n"
                + "<bigger><bigger>cool?</bigger></bigger>\n"
                + "\r\n--unique-boundary-1\r\n"
                + "Content-Type: message/rfc822\r\n"
                + "\r\n"
                + "From: (mailbox in US-ASCII)\n"
                + "To: (address in US-ASCII)\n"
                + "Subject: (subject in US-ASCII)\n"
                + "Content-Type: Text/plain; charset=ISO-8859-1\n"
                + "Content-Transfer-Encoding: Quoted-printable\n"
                + "\n"
                + "... Additional text in ISO-8859-1 goes here ...\n"
                + "\r\n--unique-boundary-1--",
                MultipartUtils.getPayload(mP).toString());
    }