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

#java #jakarta-mail #mime #multipart

#java #джакарта-почта #mime #составное

Вопрос:

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

 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 — это строка, а не составная часть или MimeMultipart . Кроме того, мне действительно не нужны все накладные расходы всего JavaMail API, мне просто нужно разобрать текст на части. Вот пример:

Это сообщение, состоящее из нескольких частей, в формате MIME.n  n------=_NextPart_000_005D_01CC73D5.3BA43FB0  N Тип содержимого: текстовый / обычный;  n  tcharset="iso-8859-1"  nКонтент-Передача-Кодирование: в кавычках-для печати nnStuff: nn Пожалуйста, прочтите этот материал вначало каждой недели. =  Не стесняйтесь обсуждать это в течение недели. n  n  n-- = 20  n  nMrs. Сьюзи М. Smithn555-555-5555nsuzy@suzy.comn------=_NextPart_000_005D_01CC73D5.3BA43FB0nContent-Type : текст/ html;n tcharset="iso-8859-1"nКонтент-Передача-Кодирование: в кавычках-для печатиnnnnnnnnnnnnStuff:

n = 20пПожалуйста, прочтите этот материал в начале каждой недели. Feel = 20 n свободно обсуждать это в течение недели.

n
--

Миссис Сьюзи М. Смит
555-555-5555
suzy@suzy.comnn------=_NextPart_000_005D_01CC73D5.3BA43FB0--nn

Ответ №1:

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

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

Комментарии:

1. Я загрузил эти банки и опробовал их. Я создал класс ContentHandler и использовал MimeStreamParser.parse. В моем обработчике вызывается startMessage, затем вызываются startHeader и endHeader, что нормально, поскольку заголовка нет. Затем вызывается body, а затем endMessage. Я ожидал бы получить там несколько начальных и конечных частей тела. Или тело вызывалось дважды, поскольку есть 2 части?

2. Я ввел некоторую информацию о заголовке, как было предложено выше в DwB, и MimeStreamParser.parse теперь отлично работает. Спасибо за информацию. Я не могу 1 вас, так как у меня недостаточно репутации…

Ответ №2:

В опубликованном вами тексте есть несколько ошибок.

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

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

Если человек, который отправляет тело, является тупицей (заменено на monkey, потому что monkey слишком субъективен — мой плохой DwB) и не будет (скорее всего, не знает, как) отправлять полное тело, вы можете получить границу, сканируя текст на строку, которая начинается и заканчивается»—» (т.е. —boundary—). Обратите внимание, что я упомянул «строку». Граница терминала на самом деле «—boundary— n».

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

Комментарии:

1. Хотя это очень информативно, я действительно ничего не могу с этим поделать. Текст приходит ко мне таким образом. Мне нужен способ его анализа, и если нет существующих инструментов, которые могли бы это сделать, я думаю, мне придется делать это вручную…

2. Введя некоторую информацию о заголовке, как вы предложили, анализатор, предложенный Ванье ниже, отлично работал. Спасибо за информацию. Я не могу 1 вас, так как у меня недостаточно репутации…

Ответ №3:

Можно создать 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 amp;amp; content instanceof String) {
            for (String bodyName : nameHeader) {
                if (bodyName.contains("name=""   name   """)) return String.valueOf(bodyPart.getContent());
            }
        }
    }
    return null;
}
  

Ответ №4:

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

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