Несмотря на засилье мессенджеров, смс и прочих скайпов, почта - наше все!
Без преувеличения.
Поэтому уметь рассылать почту на Java - архинужно и архиважно!
И в принципе, это легко сделать, но есть нюансы. как обычно=)
Теперь напишем самый простой код, присылающий сообщение на Yandex-почту:
Если выполнить этот код, то на почтовый адрес rogovdn@yandex.ru придет вот такое сообщение:
Несложно, правда? Единственное, что тут совсем непонятно, откуда берутся параметры соединения, такие как "mail.smtp.host". Но на самом деле все довольно просто. Java Mail использует для работы с почтой 3 основных протокола: SMTP - для отправки сообщений, IMAP и POP3 - для чтения. Для настройки каждого из них Java Mail имеет множество параметров, полный список которых можно посмотреть тут, тут и тут.
Пусть вас не пугает их количество, в большинстве случаев требуется лишь хост и порт сервера и параметры, связанные с аутентификацией. Поэтому запоминать их все ни к чему.
Код, конечно, стал немного сложнее, но понять его можно.
Если вы хорошо знаете HTML, то можете поразить адресата изысканным дизайном своего послания=)
Без преувеличения.
Поэтому уметь рассылать почту на Java - архинужно и архиважно!
И в принципе, это легко сделать, но есть нюансы. как обычно=)
Первые шаги
Чтобы работать с почтовыми сообщениями на Java нужно использовать замечательную библиотеку Java Mail.
Если ваш проект использует Maven, необходимо лишь добавить Java Mail в зависимости. Должно получиться что-то такое:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ru.toolkas</groupId>
<artifactId>email</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
</dependencies>
</project>
Теперь напишем самый простой код, присылающий сообщение на Yandex-почту:
package ru.toolkas.email;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
public class HelloEmail {
public static void main(String[] args) throws MessagingException {
//Объект properties хранит параметры соединения.
//Для каждого почтового сервера они разные.
//Если не знаете нужные - обратитесь к администратору почтового сервера.
//Ну или гуглите;=)
//Конкретно для Yandex параметры соединения можно подсмотреть тут:
//https://yandex.ru/support/mail/mail-clients.html (раздел "Исходящая почта")
Properties properties = new Properties();
//Хост или IP-адрес почтового сервера
properties.put("mail.smtp.host", "smtp.yandex.ru");
//Требуется ли аутентификация для отправки сообщения
properties.put("mail.smtp.auth", "true");
//Порт для установки соединения
properties.put("mail.smtp.socketFactory.port", "465");
//Фабрика сокетов, так как при отправке сообщения Yandex требует SSL-соединения
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
//Создаем соединение для отправки почтового сообщения
Session session = Session.getDefaultInstance(properties,
//Аутентификатор - объект, который передает логин и пароль
new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("rogovdn@yandex.ru", "ПАРОЛЬ");
}
});
//Создаем новое почтовое сообщение
Message message = new MimeMessage(session);
//От кого
message.setFrom(new InternetAddress("rogovdn@yandex.ru"));
//Кому
message.setRecipient(Message.RecipientType.TO, new InternetAddress("rogovdn@yandex.ru"));
//Тема письма
message.setSubject("Очень важное письмо!!!");
//Текст письма
message.setText("Hello, Email!");
//Поехали!!!
Transport.send(message);
}
}
Если выполнить этот код, то на почтовый адрес rogovdn@yandex.ru придет вот такое сообщение:
Несложно, правда? Единственное, что тут совсем непонятно, откуда берутся параметры соединения, такие как "mail.smtp.host". Но на самом деле все довольно просто. Java Mail использует для работы с почтой 3 основных протокола: SMTP - для отправки сообщений, IMAP и POP3 - для чтения. Для настройки каждого из них Java Mail имеет множество параметров, полный список которых можно посмотреть тут, тут и тут.
Пусть вас не пугает их количество, в большинстве случаев требуется лишь хост и порт сервера и параметры, связанные с аутентификацией. Поэтому запоминать их все ни к чему.
А теперь - сбрось мне файлик
Что за письма без вложений? Несерьезно даже как-то...
Но есть одна сложность: содержимое письма с вложением придется буквально собирать по частям.
У нас всего две части: текстовое сообщение внутри письма и файл-вложение.
Для того, чтобы отправить такое сообщение программно, придется поменять строчку кода
message.setText("Hello, Email!");
на код
//Файл вложения
File file = new File("D:/1.txt");
//Собираем содержимое письма из кусочков
MimeMultipart multipart = new MimeMultipart();
//Первый кусочек - текст письма
MimeBodyPart part1 = new MimeBodyPart();
part1.addHeader("Content-Type", "text/plain; charset=UTF-8");
part1.setDataHandler(new DataHandler("Письмо с файлом!!", "text/plain; charset=\"utf-8\""));
multipart.addBodyPart(part1);
//Второй кусочек - файл
MimeBodyPart part2 = new MimeBodyPart();
part2.setFileName(MimeUtility.encodeWord(file.getName()));
part2.setDataHandler(new DataHandler(new FileDataSource(file)));
multipart.addBodyPart(part2);
//Добавляем оба кусочка в сообщение
message.setContent(multipart);
Теперь, открыв почту, мы увидим файл во вложении.Код, конечно, стал немного сложнее, но понять его можно.
Наводим красоту
Теперь, когда мы умеем слать и просто сообщения и сообщения с вложениями, душа требует чего-то прекрасного, яркого и незабываемого!
Что ж, нет ничего проще, если подойти к делу с огоньком. Мы можем слать не только простой и скучный текст, но и HTML-разметку.
А это значит, что если написать, например так:
//Собираем содержимое письма из кусочков
MimeMultipart multipart = new MimeMultipart();
//Первый кусочек - текст письма
MimeBodyPart part1 = new MimeBodyPart();
part1.addHeader("Content-Type", "text/html; charset=UTF-8");
part1.setDataHandler(
new DataHandler(
"<html><body style=\"background-color: #FFFF00;color: #FF0033;\"><h1>Привет!</h1></body></html>",
"text/html; charset=\"utf-8\""
)
);
multipart.addBodyPart(part1);
message.setContent(multipart);
Запустив этот код, мы получим на почту вот такую красоту:
Если вы хорошо знаете HTML, то можете поразить адресата изысканным дизайном своего послания=)
Странные проблемы
При использовании Java Mail в сложной среде загрузчиков иногда можно встретить следующую ошибку:
Эти классы загружаются довольно специфическим образом, поэтому, чтобы помочь библиотеке найти их, можно использовать следующий трюк:
Хорошего вам программирования, отправляйте и получайте письма, экспериментируйте - во имя добра!
javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed;
boundary="----=_Part_0_347165349.1510819320461"
at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:896)
at javax.activation.DataHandler.writeTo(DataHandler.java:317)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1652)
at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1850)
at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1824)
at org.simplejavamail.converter.EmailConverter.mimeMessageToEML(EmailConverter.java:186)
... 12 common frames omitted
DCH object, который не смогла найти библиотека - это Data Content Handler, один из классов, который определяет как добавляется в сообщение содержимое того или иного формата.Эти классы загружаются довольно специфическим образом, поэтому, чтобы помочь библиотеке найти их, можно использовать следующий трюк:
package ru.toolkas.email;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.util.Properties;
public class HelloEmail {
public static void main(String[] args) throws MessagingException {
//Запомним контекстный загрузчик классов
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try {
Сделаем контекстным загрузчик, которым загружены классы библиотеки Java Mail
Thread.currentThread().setContextClassLoader(javax.mail.Session.class.getClassLoader());
Properties properties = new Properties();
properties.put("mail.smtp.host", "smtp.yandex.ru");
properties.put("mail.smtp.auth", "true");
properties.put("mail.smtp.socketFactory.port", "465");
properties.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
Session session = Session.getDefaultInstance(properties,
new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("rogovdn@yandex.ru", "ПАРОЛЬ");
}
});
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress("rogovdn@yandex.ru"));
message.setRecipient(Message.RecipientType.TO, new InternetAddress("rogovdn@yandex.ru"));
message.setSubject("Очень важное письмо!!!");
message.setText("Hello, Email!");
Transport.send(message);
} finally {
//Вернем исходный контекстный загрузчик классов
Thread.currentThread().setContextClassLoader(loader);
}
}
}
Надеюсь, этот финт сэкономит вам время и нервы и позволит дальше программировать без ошибок=)
Чтение почты
Иногда нужно не рассылать почту, а читать ее. И в этом случае Java Mail так же придет нам на помощь. Код для чтения почтовых писем не сильно сложнее, чем для отправки:
package ru.toolkas.email;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import java.util.Properties;
public class ReadEmail {
public static void main(String[] args) throws MessagingException {
//Объект properties содержит параметры соединения
Properties properties = new Properties();
//Так как для чтения Yandex требует SSL-соединения - нужно использовать фабрику SSL-сокетов
properties.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
//Создаем соединение для чтения почтовых сообщений
Session session = Session.getDefaultInstance(properties);
//Это хранилище почтовых сообщений. По сути - это и есть почтовый ящик=)
Store store = null;
try {
//Для чтения почтовых сообщений используем протокол IMAP.
//Почему? Так Yandex сказал: https://yandex.ru/support/mail/mail-clients.html
//см. раздел "Входящая почта"
store = session.getStore("imap");
//Подключаемся к почтовому ящику
store.connect("imap.yandex.ru", 993, "rogovdn@yandex.ru", "ПАРОЛЬ");
//Это папка, которую будем читать
Folder inbox = null;
try {
//Читаем папку "Входящие сообщения"
inbox = store.getFolder("INBOX");
//Будем только читать сообщение, не меняя их
inbox.open(Folder.READ_ONLY);
//Получаем количество сообщения в папке
int count = inbox.getMessageCount();
//Вытаскиваем все сообщения с первого по последний
Message[] messages = inbox.getMessages(1, count);
//Циклом пробегаемся по всем сообщениям
for (Message message : messages) {
//От кого
String from = ((InternetAddress) message.getFrom()[0]).getAddress();
System.out.println("FROM: " + from);
//Тема письма
System.out.println("SUBJECT: " + message.getSubject());
}
} finally {
if (inbox != null) {
//Не забываем закрыть собой папку сообщений.
inbox.close(false);
}
}
} finally {
if (store != null) {
//И сам почтовый ящик тоже закрываем
store.close();
}
}
}
}
Вот таким простым способом можно прочитать содержимое почтового ящика=)
Конец
Итак, друзья, на этом заканчивается мое короткое введение в библиотеку Java Mail.
Хорошего вам программирования, отправляйте и получайте письма, экспериментируйте - во имя добра!
спасибо!
ОтветитьУдалитьВсегда пожалуйста))
УдалитьКруто!
ОтветитьУдалитьЗдравствуйте! Спасибо большое за код! Антивирус конечно уничтожал мои клетки, но я смог совладать с собой и снес его!Может ли Imap сохранять вложения входящих писем, или нужно изменить Properties изменить? Я заимствовал код по скачке и у меня сохранялся заголовок файла типа "ЛР.odt", но поток был пуст, как и файл.Или я что-то не доделал?
ОтветитьУдалитьДобрый день!
УдалитьВложения можно сохранит приблизительно так:
package ru.documentum.business.services;
import org.apache.commons.lang.StringUtils;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
public class SaveAttachments {
private static void saveAttachments(Session session, Message message, File dir) throws MessagingException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
message.writeTo(baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
MimeMessage mimeMessage = new MimeMessage(session, bais);
Multipart multipart = (Multipart) mimeMessage.getContent();
for (int index = 0; index < multipart.getCount(); index++) {
MimeBodyPart part = (MimeBodyPart) multipart.getBodyPart(index);
if (StringUtils.isNotBlank(part.getFileName())) {
String fileName = MimeUtility.decodeText(part.getFileName());
File f = new File(dir, fileName);
part.saveFile(f);
}
}
}
}
пригодится?
ОтветитьУдалитьhttps://stackoverflow.com/questions/2996514/inline-images-in-email-using-javamail
""
MimeBodyPart imagePart = new MimeBodyPart();
imagePart.attachFile("resources/teapot.jpg");
imagePart.setContentID("<" + cid + ">");
imagePart.setDisposition(MimeBodyPart.INLINE);
content.addBodyPart(imagePart);
Привет! Этот трюк с ClassLoader не помогает. Что ещё можно сделать? К слову, в IDE вложение отправляется, как только я собираю jar и делаю из него .exe, запускаю его на сервере, в лог вылетает это исключение "javax.activation.UnsupportedDataTypeException: no object DCH for MIME type multipart/mixed;". Не понимаю в чем магия, в IDE работает в jar нет. Это зависит от того, что библиотека не может найти файлы для прикрепления или не может их прочитать?
ОтветитьУдалитьДобрый день, Никита!
УдалитьКод полностью как в статье или с вариациями?
опишите окружение, ось, Java, Антивирус?
Добрый день! В моем приложении код был естественно с вариациями. Но ради эксперимента, я с копипастил. Результата за приделами IDE не было, т.е. в IDE(Idea) все работает, вне нет. Нашел на стеке (https://stackoverflow.com/questions/21856211/javax-activation-unsupporteddatatypeexception-no-object-dch-for-mime-type-multi) вот такую формацию:
УдалитьMailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822");
Вставил в конструктор класса и всё работает. До конца не понимаю, что такое MailCamp, не сталкивались с этим? Если да, можете пожалуйста вкратце объяснить?
Как мне Message[], отправить на фронт в формате Json ? Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Not connected; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Not connected (through reference chain: java.util.Arrays$ArrayList[0]->com.sun.mail.imap.IMAPMessage["folder"]->com.sun.mail.imap.IMAPFolder["store"]->com.sun.mail.imap.IMAPStore["sharedNamespaces"])]
ОтветитьУдалить