Несколько лет назад мне нужно было написать Java-приложение, которое получает электронные письма и обрабатывает в них некоторые бизнес-материалы. Это была непростая задача, так как я не нашел много информации. Из-за этого я решил, что однажды напишу об этом и, может быть, это могло бы помочь..
Доступен полный исходный код здесь .
Почему?
Вы бы спросили, зачем вам это нужно? Я бы сказал:
Бизнес-требования могут удивлять вас каждый день
Ниже приведен небольшой список некоторых случаев использования, когда обработка входящих писем может быть полезной.
- Тестирование: Может быть хорошим вариантом для интеграционного тестирования возможностей электронной почты ваших сервисов/приложений ( Старый FakeSMTP является хорошим примером графического интерфейса)
- Проанализируйте полученные электронные письма и извлеките некоторую конкретную информацию
- …
Что?
SubEthaSMTP – это низкоуровневый API для написания практически любого приложения для приема почты SMTP.
Чтобы избежать долгой презентации истории, самая обновленная версия subethaedit SMTP – это форк от Davidmoten (большое спасибо ему за отличную работу и обновление этой библиотеки). Мы будем использовать эту вилку в этом посте.
Я думаю, что нет необходимости описывать, что такое Весенний ботинок в наши дни.
Перед запуском кода я предлагаю посмотреть, как мы можем отправить электронное письмо через терминал. Это нам понадобится, чтобы отправить электронное письмо в наше будущее приложение для получения электронной почты.
Отправить электронное письмо с помощью cURL
Ниже приведен пример отправки электронной почты на определенный почтовый сервер с такими параметрами, как от, получатель, авторизация и содержимое электронной почты.
curl --url 'smtp://localhost:25000' \ --mail-from 'customer-address@mail.com' \ --mail-rcpt 'info@marketing.company.com' \ --user 'superus3r:passw0rd' \ -T <(echo -e 'From: customer-address@mail.com\nTo: info@marketing.company.com\nSubject: cURL Test\n\nHello, this is the content')
Зависимость от Субэта
Здесь мы добавляем зависимость maven от SMTP SubEtha.
com.github.davidmoten subethasmtp 5.2.4
Запустите встроенный SMTP-сервер
С помощью библиотеки очень легко запустить простой SMTP-сервер. Просто создайте/создайте экземпляр SMTP-сервера с правильными параметрами, такими как порт, и запустите этот экземпляр.
// Build the embedded SMTP server SMTPServer smtpServer = SMTPServer.port(25000).build(); // Start server asynchronously smtpServer.start();
Теперь наш SMTP-сервер запущен, но не полностью готов к приему электронной почты. Нам нужно реализовать MessageListener для извлечения важных данных, таких как из и адреса получателя , но также тема и тело полученного электронного письма.
Для этого мы можем реализовать интерфейс SimpleMessageListener :
public class MarketingMailListener implements SimpleMessageListener { private static final String MARKETING_DOMAIN = "@marketing.company.com"; /** * Do some business logic here */ @Override public boolean accept(String from, String recipient) { return recipient != null && recipient.endsWith(MARKETING_DOMAIN); } @Override public void deliver(String from, String recipient, InputStream data) throws TooMuchDataException, IOException { System.out.println("deliver message of MARKETING department"); System.out.println("From : "+from); System.out.println("Recipient : "+recipient); }
Как вы можете видеть здесь, я добавил простое бизнес-правило внутри метода принять для обработки только электронных писем, отправленных в отдел маркетинга.
Метод accept отвечает за определение того, будет ли полученное сообщение обработано этим слушателем или нет.
Метод доставки отвечает за извлечение:
- От : Адрес отправителя
- Получатель : Адрес получателя
- Данные : Это тип входного потока, из которого мы можем извлекать содержимое и соответствующую информацию, связанную с полученным электронным письмом, например: тема, текст, CC, вложения и прочее.
Давайте посмотрим, как мы можем извлечь содержимое электронного письма:
Преобразовать в MimeMessage
Мы можем извлекать содержимое из составного сообщения с типизированным содержимым, используя экземпляр MimeMessage.
public MimeMessage convertToMimeMessage(InputStream data) throws MessagingException { Session session = Session.getDefaultInstance(new Properties()); try { return new MimeMessage(session, data); }catch (MessagingException e){ throw new MessagingException(); } }
Извлечение содержимого электронной почты
Чтобы извлечь содержимое электронной почты, мы создадим модель Полученное электронное письмо для облегчения обработки.
public class ReceivedEmail { private String subject; private String senderAddress; private String senderName; private String recipientAddress; private String recipientName; private String cc; private String bcc; private String contentType; private Listattachments = new ArrayList(); // Getters and setters // ... }
Для простоты я использовал Строка для адреса получателя, CC и BCC но это может быть список адресов (пример в коде ).
Мы создаем специальный сервис для извлечения содержимого электронной почты, и метод извлечения может выглядеть следующим образом:
public ReceivedEmail extractReceivedEmail(InputStream data) throws Exception { ReceivedEmail receivedEmail = new ReceivedEmail(); MimeMessage message; try { message = this.convertToMimeMessage(data); receivedEmail.setSubject(message.getSubject()); receivedEmail.setSenderAddress(InternetAddress.toString(message.getFrom())); InternetAddress[] recipientAddresses = InternetAddress.parse(InternetAddress.toString(message.getAllRecipients())); receivedEmail.setRecipientAddress(InternetAddress.toString(recipientAddresses)); receivedEmail.setRecipientName(recipientAddresses[0].getPersonal()); receivedEmail.setContentType(message.getContentType()); // Use here Apache library for parsing MimeMessageParser messageParser = new MimeMessageParser(message); messageParser.parse(); // very important to parse before getting data receivedEmail.setCc(messageParser.getCc().toString()); receivedEmail.setBcc(messageParser.getBcc().toString()); receivedEmail.setAttachments(messageParser.getAttachmentList()); System.out.println(receivedEmail); return receivedEmail; } catch (Exception e) { throw new Exception(); } }
Теперь у нас есть полноценный приемник электронной почты с минимальными строками кода.
Защищенный SMTP-сервер
Давайте сделаем еще один шаг, чтобы узнать, как мы можем защитить наш почтовый сервер.
Первое, что нужно сделать, это указать, что требуется аутентификация, и реализовать базовую аутентификацию с помощью имени пользователя и пароля.
this.smtpServer = SMTPServer .port(25000) .simpleMessageListener(marketingMsgListener) .requireAuth(true) // auth required .authenticationHandlerFactory(easyAuth) // implement type of auth .build();
Могут быть выполнены различные реализации authenticationhandlerfactory , я выбрал здесь, опять же для простоты, класс EasyAuthenticationHandlerFactory , для которого требуется реализация интерфейса UserNamePasswordValidator .
@Configuration public class SimpleAuthValidatorImpl implements UsernamePasswordValidator { private final String CREDENTIALS_LOGIN = "superus3r"; private final String CREDENTIALS_PASSWORD = "passw0rd"; @Override public void login(String username, String password, MessageContext context) throws LoginFailedException { if(CREDENTIALS_LOGIN.equals(username) && CREDENTIALS_PASSWORD.equals(password)){ System.out.println("Authenticated successfully"); }else{ System.err.println("Invalid authentication !"); throw new LoginFailedException(); } } }
И вот как выглядит наша конфигурация SMTP-сервера :
@Configuration public class SMTPServerConfig { private final SMTPServer smtpServer; private final SimpleMessageListener marketingMsgListener; private final UsernamePasswordValidator authValidator; private final EasyAuthenticationHandlerFactory easyAuth; public SMTPServerConfig(SimpleMessageListener marketingMsgListener) { authValidator = new SimpleAuthValidatorImpl(); easyAuth = new EasyAuthenticationHandlerFactory(authValidator); this.marketingMsgListener = marketingMsgListener; this.smtpServer = SMTPServer .port(25000) .simpleMessageListener(this.marketingMsgListener) .requireAuth(true) .authenticationHandlerFactory(easyAuth) .build(); this.smtpServer.start(); } }
Дополнительные параметры могут быть настроены в соответствии с вашими потребностями и улучшением вашего сервера SubEtha, я перечисляю их ниже, и вы можете попробовать изучить их, чтобы улучшить реализацию вашего почтового получателя.:
- Максимальное количество подключений и время ожидания подключения
- Поддержка TLS
- Размер сообщений
- Завершение работы SMTP-сервера
- Тестирование
Я представил, как мы можем с помощью небольших строк кода написать приложение, которое может получать электронные письма, обрабатывать их и применять к ним некоторую магию с помощью SubEtha SMTP и Spring Boot.
Если у вас есть какие-либо вопросы или предложения, пожалуйста, оставьте свои комментарии ниже.
Спасибо за чтение и счастливого кодирования.
Исходный код: https://github.com/redamessoudi/subethasmtp-springboot .
Фотография в заголовке Лиам Труонг на Unsplash
Оригинал: “https://dev.to/reda/receive-emails-with-subetha-smtp-and-spring-boot-2b8”