Невозможно проанализировать это тело сообщения mime, состоящее из нескольких частей, в Java

Я не пишу почтовое приложение, поэтому у меня нет доступа ко всем заголовкам и тому подобному. Все, что у меня есть, это что-то вроде блока в конце этого вопроса. Я попытался использовать API JavaMail для анализа этого, используя что-то вроде

Session s = Session.getDefaultInstance(new Properties());
InputStream is = new ByteArrayInputStream(<< String to parse >>);
MimeMessage message = new MimeMessage(s, is);
Multipart multipart = (Multipart) message.getContent();

Но это просто говорит мне, что message.getContent - это String, а не Multipart или MimeMultipart. Кроме того, мне действительно не нужны все накладные расходы всего API JavaMail, мне просто нужно разобрать текст на его части. Вот пример:

This is a multi-part message in MIME format.\n\n------=_NextPart_000_005D_01CC73D5.3BA43FB0\nContent-Type: text/plain;\n\tcharset="iso-8859-1"\nContent-Transfer-Encoding: quoted-printable\n\nStuff:\n\n            Please read this stuff at the beginning of each week.  =\nFeel free to discuss it throughout the week.\n\n\n--=20\n\nMrs. Suzy M. Smith\n555-555-5555\[email protected]\n------=_NextPart_000_005D_01CC73D5.3BA43FB0\nContent-Type: text/html;\n\tcharset="iso-8859-1"\nContent-Transfer-Encoding: quoted-printable\n\n\n\n\n\n\n\n\n\nStuff:

\n           =20\nPlease read this stuff at the beginning of each =\nweek.  Feel=20\nfree to discuss it throughout the week.

\n
--

Mrs. Suzy M. Smith
555-555-5555
[email protected]\n\n------=_NextPart_000_005D_01CC73D5.3BA43FB0--\n\n

person Bynan    schedule 06.10.2011    source источник


Ответы (4)


В тексте, который вы разместили, есть несколько ошибок.

Это не допустимый составной мим. Ознакомьтесь с ссылкой на Википедию, которая, хотя и не является нормативной, все же является правильной.

Граница пантомимы не определена. Из примера из Википедии: Content-Type: multipart/mixed; boundary="frontier" показывает, что граница является «границей». В вашем примере "----=_NextPart_000_005D_01CC73D5.3BA43FB0" является границей, но это можно определить только путем сканирования текста (т.е. мим искажен). Вы должны проинструктировать дурака, который передает вам содержимое пантомимы, что вам также необходимо знать граничное значение пантомимы, которое не определено в заголовке сообщения. Если вы получите все тело сообщения, вам будет достаточно, потому что тело сообщения начинается с MIME-Version: 1.0, за которым следует Content-Type: multipart/mixed; boundary="frontier", где граница будет заменена значением границы для закодированного пантомимы.

Если человек, который отправляет тело, является болваном (перешел с обезьяны, потому что обезьяна слишком осуждающая - мой плохой DwB) и не будет (скорее всего, не знает, как) отправить полное тело, вы можете получить границу, отсканировав текст в поисках строки, которая начинается и заканчивается "--" (ie --boundary--). Обратите внимание, что я упомянул «линию». Конечная граница на самом деле "--boundary--\n".

Наконец, материал, который вы разместили, состоит из 2 частей. Первая часть, по-видимому, определяет замены, которые должны иметь место во второй части. Если это так, Content-Type: первой части, вероятно, должен быть чем-то отличным от «text/plain». Возможно, «название компании/подстановка-определение» или что-то в этом роде. Это позволит использовать несколько (как в будущих улучшениях) форматов замены.

person DwB    schedule 06.10.2011
comment
Хотя это очень информативно, я ничего не могу с этим поделать. Текст приходит ко мне таким образом. Мне нужен способ разобрать его, и если нет существующих инструментов, которые могли бы это сделать, я думаю, мне придется сделать это вручную... - person Bynan; 07.10.2011
comment
Поместив некоторую информацию заголовка, как вы предложили, синтаксический анализатор, предложенный vanje ниже, отлично работал. Спасибо за информацию. Я не могу добавить вам +1, так как у меня недостаточно представителей... - person Bynan; 07.10.2011

Сначала я взял ваше примерное сообщение и заменил все вхождения \n символами новой строки и \t вкладками.

Затем я загрузил файлы JAR из проекта Mime4J, подпроекта Apache James и выполнил анализ GUI пример org.apache.james.mime4j.samples.tree.MessageTree с преобразованное сообщение выше в качестве входных данных. И, по-видимому, Mime4J смог проанализировать сообщение и извлечь часть сообщения HTML.

person vanje    schedule 06.10.2011
comment
Я скачал эти JAR-файлы и попробовал их. Я создал класс ContentHandler и использовал MimeStreamParser.parse. В моем обработчике вызывается startMessage, затем вызываются startHeader и endHeader, что нормально, поскольку заголовка нет. Затем вызывается body, а затем endMessage. Я бы ожидал, что там будут некоторые начальные и конечные части тела. Или вызвать тело дважды, так как есть 2 части? - person Bynan; 07.10.2011
comment
Я поместил некоторую информацию заголовка, как это было предложено DwB выше, и теперь MimeStreamParser.parse отлично работает. Спасибо за информацию. Я не могу добавить вам +1, так как у меня недостаточно представителей... - person Bynan; 07.10.2011

Можно создать MimeMultipart из http-запроса.

javax.mail.internet.MimeMultipart m = new MimeMultipart(new ServletMultipartDataSource(httpRequest));

public class ServletMultipartDataSource implements DataSource {
    String contentType;
    InputStream inputStream;
    public ServletMultipartDataSource(ServletRequest request) throws IOException {
        inputStream = new SequenceInputStream(new ByteArrayInputStream("\n".getBytes()), request.getInputStream());
        contentType = request.getContentType();
    }
    public InputStream getInputStream() throws IOException {
        return inputStream;
    }
    public OutputStream getOutputStream() throws IOException {
        return null;
    }
    public String getContentType() {
        return contentType;
    }
    public String getName() {
        return "ServletMultipartDataSource";
    }
}

Для получения параметра отправленной формы необходимо разобрать заголовки BodyPart:

public String getStringParameter(String name) throws MessagingException, IOException {
    for (int i = 0; i < getCount(); i++) {
        BodyPart bodyPart = m.getBodyPart(i);
        String[] nameHeader = bodyPart.getHeader("Content-Disposition");
        if (nameHeader != null && content instanceof String) {
            for (String bodyName : nameHeader) {
                if (bodyName.contains("name=\"" + name + "\"")) return String.valueOf(bodyPart.getContent());
            }
        }
    }
    return null;
}
person timtish    schedule 16.08.2012

Если вы используете javax.servlet.http.HttpServlet для получения сообщения, вам придется использовать HttpServletRequests.getHeaders для получения значения типа содержимого заголовка HTTP. Затем вы будете использовать org.apache.james.mime4j.stream.MimeConfig.setHeadlessParsing для установки MimeConfig с информацией, чтобы он мог правильно обрабатывать сообщение mime.

Похоже, вы используете HttpServletRequest.getInputStream для чтения содержимого запроса. Возвращаемый входной поток содержит только содержимое сообщения после заголовков HTTP (заканчивающихся пустой строкой). Вот почему вы должны извлечь тип содержимого из заголовков HTTP и передать его анализатору с помощью setHeadlessParsing.

person Bradley Ross    schedule 02.11.2012