Как читать текст внутри тела почты с помощью javax.mail
Я разрабатываю почтовую почту клиента, используя javax.mail для чтения почты внутри почтового ящика:
Properties properties = System.getProperties();
properties.setProperty("mail.store.protocol", "imap");
try {
Session session = Session.getDefaultInstance(properties, null);
Store store = session.getStore("pop3");//create store instance
store.connect("pop3.domain.it", "mail.it", "*****");
Folder inbox = store.getFolder("inbox");
FlagTerm ft = new FlagTerm(new Flags(Flags.Flag.SEEN), false);
inbox.open(Folder.READ_ONLY);//set access type of Inbox
Message messages[] = inbox.search(ft);
String mail,sub,bodyText="";
Object body;
for(Message message:messages) {
mail = message.getFrom()[0].toString();
sub = message.getSubject();
body = message.getContent();
//bodyText = body.....
}
} catch (Exception e) {
System.out.println(e);
}
Я знаю, что метод getContent()
возвращает объект, потому что контент может быть String
, a MimeMultiPart
, a SharedByteArrayInputstream
и другие (я думаю)... Есть ли способ всегда получать текст внутри тела сообщения? Благодарю!!
Ответы
Ответ 1
Этот ответ расширяет ответ yurin. Вопрос, который он затронул, состоял в том, что содержимое MimeMultipart
может быть другим MimeMultipart
. Ниже описан метод getTextFromMimeMultipart()
в таких случаях на контенте, пока тело сообщения не будет полностью проанализировано.
private String getTextFromMessage(Message message) throws MessagingException, IOException {
String result = "";
if (message.isMimeType("text/plain")) {
result = message.getContent().toString();
} else if (message.isMimeType("multipart/*")) {
MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
result = getTextFromMimeMultipart(mimeMultipart);
}
return result;
}
private String getTextFromMimeMultipart(
MimeMultipart mimeMultipart) throws MessagingException, IOException{
String result = "";
int count = mimeMultipart.getCount();
for (int i = 0; i < count; i++) {
BodyPart bodyPart = mimeMultipart.getBodyPart(i);
if (bodyPart.isMimeType("text/plain")) {
result = result + "\n" + bodyPart.getContent();
break; // without break same text appears twice in my tests
} else if (bodyPart.isMimeType("text/html")) {
String html = (String) bodyPart.getContent();
result = result + "\n" + org.jsoup.Jsoup.parse(html).text();
} else if (bodyPart.getContent() instanceof MimeMultipart){
result = result + getTextFromMimeMultipart((MimeMultipart)bodyPart.getContent());
}
}
return result;
}
Ответ 2
Этот ответ расширяет ответ остина, чтобы исправить первоначальную проблему с лечением multipart/alternative
(// without break same text appears twice in my tests
).
Текст появляется дважды, потому что для multipart/alternative
пользовательский агент должен выбирать только одну часть.
С RFC2046:
Тип "multipart/alternative" синтаксически идентичен типу "multipart/mixed", но семантика различна. В частности, каждая из частей тела является "альтернативной" версией той же информации.
Системы должны понимать, что содержимое различных частей взаимозаменяемо. Системы должны выбирать "лучший" тип на основе локальной среды и ссылок, в некоторых случаях даже через взаимодействие с пользователем. Как и в случае "multipart/mixed", порядок частей тела является значительным. В этом случае альтернативы появляются в порядке возрастания точности исходного контента. В общем, лучшим выбором является LAST-часть типа, поддерживаемого локальной средой системы получателя.
Тот же пример с обработкой альтернатив:
private String getTextFromMessage(Message message) throws IOException, MessagingException {
String result = "";
if (message.isMimeType("text/plain")) {
result = message.getContent().toString();
} else if (message.isMimeType("multipart/*")) {
MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
result = getTextFromMimeMultipart(mimeMultipart);
}
return result;
}
private String getTextFromMimeMultipart(
MimeMultipart mimeMultipart) throws IOException, MessagingException {
int count = mimeMultipart.getCount();
if (count == 0)
throw new MessagingException("Multipart with no body parts not supported.");
boolean multipartAlt = new ContentType(mimeMultipart.getContentType()).match("multipart/alternative");
if (multipartAlt)
// alternatives appear in an order of increasing
// faithfulness to the original content. Customize as req'd.
return getTextFromBodyPart(mimeMultipart.getBodyPart(count - 1));
String result = "";
for (int i = 0; i < count; i++) {
BodyPart bodyPart = mimeMultipart.getBodyPart(i);
result += getTextFromBodyPart(bodyPart);
}
return result;
}
private String getTextFromBodyPart(
BodyPart bodyPart) throws IOException, MessagingException {
String result = "";
if (bodyPart.isMimeType("text/plain")) {
result = (String) bodyPart.getContent();
} else if (bodyPart.isMimeType("text/html")) {
String html = (String) bodyPart.getContent();
result = org.jsoup.Jsoup.parse(html).text();
} else if (bodyPart.getContent() instanceof MimeMultipart){
result = getTextFromMimeMultipart((MimeMultipart)bodyPart.getContent());
}
return result;
}
Обратите внимание, что это очень простой пример. Он пропускает множество случаев и не должен использоваться в производстве в его нынешнем формате.
Ответ 3
Я так не думаю, иначе что произойдет, если тип mime Part
- image/jpeg
? API возвращает Object
, потому что внутренне он пытается дать вам что-то полезное, если вы знаете, что ожидается. Для программного обеспечения общего назначения оно предназначено для использования следующим образом:
if (part.isMimeType("text/plain")) {
...
} else if (part.isMimeType("multipart/*")) {
...
} else if (part.isMimeType("message/rfc822")) {
...
} else {
...
}
У вас также есть необработанный (на самом деле не такой сырой, см. Javadoc) Part.getInputStream()
, но я считаю, что небезопасно предполагать, что каждый и каждое полученное сообщение является текстовым, если вы не пишете очень специфическое приложение, и у вас есть контроль над источником ввода.
Ответ 4
Ниже приведен метод, который будет принимать текст из сообщения, если bodyParts - текст и html.
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.internet.MimeMultipart;
import org.jsoup.Jsoup;
....
private String getTextFromMessage(Message message) throws Exception {
if (message.isMimeType("text/plain")){
return message.getContent().toString();
}else if (message.isMimeType("multipart/*")) {
String result = "";
MimeMultipart mimeMultipart = (MimeMultipart)message.getContent();
int count = mimeMultipart.getCount();
for (int i = 0; i < count; i ++){
BodyPart bodyPart = mimeMultipart.getBodyPart(i);
if (bodyPart.isMimeType("text/plain")){
result = result + "\n" + bodyPart.getContent();
break; //without break same text appears twice in my tests
} else if (bodyPart.isMimeType("text/html")){
String html = (String) bodyPart.getContent();
result = result + "\n" + Jsoup.parse(html).text();
}
}
return result;
}
return "";
}
Обновление. Есть случай, что сам bodyPart может быть типа multipart. (Я встретил такое письмо после того, как написал этот ответ.) В этом случае вам потребуется переписать выше метод с рекурсией.
Ответ 5
Не изобретай велосипед! Вы можете просто использовать электронную почту Apache Commons (см. здесь)
Пример Kotlin:
fun readHtmlContent(message: MimeMessage) =
MimeMessageParser(message).parse().htmlContent
Если электронное письмо не содержит html-содержимого, но содержит простое содержимое (вы можете проверить это с помощью методов hasPlainContent и hasHtmlContent), вам следует использовать этот код:
fun readPlainContent(message: MimeMessage) =
MimeMessageParser(message).parse().plainContent
Пример Java:
String readHtmlContent(MimeMessage message) throws Exception {
return new MimeMessageParser(message).parse().getHtmlContent();
}
String readPlainContent(MimeMessage message) throws Exception {
return new MimeMessageParser(message).parse().getPlainContent();
}
Ответ 6
Если вы хотите всегда получать текст, вы можете пропустить другие типы, такие как "multipart" и т.д.
Object body = message.getContent();
if(body instanceof String){
// hey it a text
}
Ответ 7
Мой ответ - расширенная версия Ответа Остина, но с одним условием в первом методе (getTextFromMessage()).
Изменение: мы также должны проверить, является ли MimeType "text/html".
проверить строки, заканчивающиеся на "//" **
private String getTextFromMessage(Message message) throws MessagingException, IOException {
String result = "";
if (message.isMimeType("text/plain")) {
result = message.getContent().toString();
}
else if (message.isMimeType("text/html")) { // **
result = message.getContent().toString(); // **
}
else if (message.isMimeType("multipart/*")) {
MimeMultipart mimeMultipart = (MimeMultipart) message.getContent();
result = getTextFromMimeMultipart(mimeMultipart);
}
return result;
}
private String getTextFromMimeMultipart(
MimeMultipart mimeMultipart) throws MessagingException, IOException{
String result = "";
int count = mimeMultipart.getCount();
for (int i = 0; i < count; i++) {
BodyPart bodyPart = mimeMultipart.getBodyPart(i);
if (bodyPart.isMimeType("text/plain")) {
result = result + "\n" + bodyPart.getContent();
break; // without break same text appears twice in my tests
} else if (bodyPart.isMimeType("text/html")) {
String html = (String) bodyPart.getContent();
result = result + "\n" + org.jsoup.Jsoup.parse(html).text();
} else if (bodyPart.getContent() instanceof MimeMultipart){
result = result + getTextFromMimeMultipart((MimeMultipart)bodyPart.getContent());
}
}
return result;
}