From 675c5fded881996911a94ab7b118f7f9c5edc3f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Thu, 28 Nov 2024 14:32:47 +0100 Subject: [PATCH 1/6] Split session initialization from mail sending MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël L'hopital --- .../mail/internal/MailBindingConstants.java | 6 +- .../binding/mail/internal/SMTPHandler.java | 96 ++++++++++++------- 2 files changed, 65 insertions(+), 37 deletions(-) diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailBindingConstants.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailBindingConstants.java index f31afccfa71ab..6dc437956058e 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailBindingConstants.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailBindingConstants.java @@ -12,8 +12,6 @@ */ package org.openhab.binding.mail.internal; -import java.util.Arrays; -import java.util.HashSet; import java.util.Set; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -34,8 +32,8 @@ public class MailBindingConstants { public static final ThingTypeUID THING_TYPE_IMAPSERVER = new ThingTypeUID(BINDING_ID, "imap"); public static final ThingTypeUID THING_TYPE_POP3SERVER = new ThingTypeUID(BINDING_ID, "pop3"); - public static final Set SUPPORTED_THING_TYPES = new HashSet<>( - Arrays.asList(THING_TYPE_SMTPSERVER, THING_TYPE_IMAPSERVER, THING_TYPE_POP3SERVER)); + public static final Set SUPPORTED_THING_TYPES = Set.of(THING_TYPE_SMTPSERVER, THING_TYPE_IMAPSERVER, + THING_TYPE_POP3SERVER); public static final ChannelTypeUID CHANNEL_TYPE_UID_FOLDER_MAILCOUNT = new ChannelTypeUID(BINDING_ID, "mailcount"); public static final ChannelTypeUID CHANNEL_TYPE_UID_MAIL_CONTENT = new ChannelTypeUID(BINDING_ID, "content"); diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java index fd529b15686ec..efa3cad4f6678 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java @@ -21,17 +21,21 @@ import javax.activation.PatchedMailcapCommandMap; import javax.mail.MessagingException; import javax.mail.Part; +import javax.mail.Session; import javax.mail.internet.MimeMultipart; import org.apache.commons.mail.DefaultAuthenticator; import org.apache.commons.mail.Email; import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.SimpleEmail; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.mail.internal.action.SendMailActions; import org.openhab.binding.mail.internal.config.SMTPConfig; import org.openhab.core.thing.ChannelUID; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; +import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.binding.BaseThingHandler; import org.openhab.core.thing.binding.ThingHandlerService; import org.openhab.core.types.Command; @@ -45,13 +49,15 @@ * @author Jan N. Klug - Initial contribution * @author Hans-Jörg Merk - Fixed UnsupportedDataTypeException - Originally by Jan N. Klug * - Fix sending HTML/Multipart mail - Originally by Jan N. Klug + * @author Gaël L'hopital - Added session initialization for thing status check */ @NonNullByDefault public class SMTPHandler extends BaseThingHandler { private final Logger logger = LoggerFactory.getLogger(SMTPHandler.class); private final PatchedMailcapCommandMap commandMap = new PatchedMailcapCommandMap(); - private @NonNullByDefault({}) SMTPConfig config; + private String sender = ""; + private @Nullable Session session; public SMTPHandler(Thing thing) { super(thing); @@ -63,19 +69,53 @@ public void handleCommand(ChannelUID channelUID, Command command) { @Override public void initialize() { - config = getConfigAs(SMTPConfig.class); + updateStatus(ThingStatus.UNKNOWN); - if (config.port == 0) { - if (config.security == ServerSecurity.SSL) { - config.port = 465; - } else { - config.port = 25; - } + SMTPConfig config = getConfigAs(SMTPConfig.class); + if (config.sender instanceof String confSender) { + sender = confSender; + } + + Email mail = new SimpleEmail(); + mail.setHostName(config.hostname); + + int port = config.port != 0 ? config.port : config.security == ServerSecurity.SSL ? 465 : 25; + switch (config.security) { + case SSL: + mail.setSSLOnConnect(true); + mail.setSslSmtpPort(Integer.toString(port)); + break; + case STARTTLS: + mail.setStartTLSEnabled(true); + mail.setStartTLSRequired(true); + mail.setSmtpPort(port); + break; + case PLAIN: + mail.setSmtpPort(port); + } + + if (!(config.username.isEmpty() || config.password.isEmpty())) { + mail.setAuthenticator(new DefaultAuthenticator(config.username, config.password)); + } + + Session localSession; + try { + localSession = mail.getMailSession(); + localSession.getTransport().connect(); + } catch (EmailException | MessagingException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); + return; } + this.session = localSession; updateStatus(ThingStatus.ONLINE); } + @Override + public void dispose() { + session = null; + } + /** * use this server to send a mail * @@ -83,32 +123,26 @@ public void initialize() { * @return true if successful, false if failed */ public boolean sendMail(Email mail) { + Session localSession = session; + if (localSession == null) { + logger.warn("Thing {} is not ONLINE, can't send mail", thing.getUID()); + return false; + } + + mail.setMailSession(localSession); + try { - if (mail.getFromAddress() == null) { - mail.setFrom(config.sender); - } - mail.setHostName(config.hostname); - switch (config.security) { - case SSL: - mail.setSSLOnConnect(true); - mail.setSslSmtpPort(config.port.toString()); - break; - case STARTTLS: - mail.setStartTLSEnabled(true); - mail.setStartTLSRequired(true); - mail.setSmtpPort(config.port); - break; - case PLAIN: - mail.setSmtpPort(config.port); - } - if (!config.username.isEmpty() && !config.password.isEmpty()) { - mail.setAuthenticator(new DefaultAuthenticator(config.username, config.password)); + if (mail.getFromAddress() == null && !sender.isEmpty()) { + mail.setFrom(sender); + } else { + logger.warn("No sender defined, can't send mail"); + return false; } - mail.buildMimeMessage(); // fix command map not available DataHandler dataHandler = mail.getMimeMessage().getDataHandler(); + dataHandler.setCommandMap(commandMap); try { DataSource dataSource = dataHandler.getDataSource(); @@ -127,11 +161,7 @@ public boolean sendMail(Email mail) { mail.sendMimeMessage(); } catch (MessagingException | EmailException e) { Throwable cause = e.getCause(); - if (cause != null) { - logger.warn("{}", cause.toString()); - } else { - logger.warn("{}", e.getMessage()); - } + logger.warn("{}", cause != null ? cause.toString() : e.getMessage()); return false; } return true; From d124f52a4bc0e4c6e8f257d6e5019f204d74d201 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Thu, 28 Nov 2024 14:40:28 +0100 Subject: [PATCH 2/6] Small corrections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël L'hopital --- .../java/org/openhab/binding/mail/internal/SMTPHandler.java | 1 - .../org/openhab/binding/mail/internal/config/BaseConfig.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java index efa3cad4f6678..086698b1f4e28 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java @@ -142,7 +142,6 @@ public boolean sendMail(Email mail) { // fix command map not available DataHandler dataHandler = mail.getMimeMessage().getDataHandler(); - dataHandler.setCommandMap(commandMap); try { DataSource dataSource = dataHandler.getDataSource(); diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/BaseConfig.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/BaseConfig.java index 3754c61d9851e..2c910b7884865 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/BaseConfig.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/BaseConfig.java @@ -24,7 +24,7 @@ @NonNullByDefault public class BaseConfig { public @Nullable String hostname; - public Integer port = 0; + public int port = 0; public String username = ""; public String password = ""; public ServerSecurity security = ServerSecurity.PLAIN; From 4e808cd8caf4e457a4dfae5a22d66a1ae40358e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Thu, 28 Nov 2024 14:45:22 +0100 Subject: [PATCH 3/6] Close the session transport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël L'hopital --- .../openhab/binding/mail/internal/SMTPHandler.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java index 086698b1f4e28..5cc7736e42c93 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java @@ -24,7 +24,6 @@ import javax.mail.Session; import javax.mail.internet.MimeMultipart; -import org.apache.commons.mail.DefaultAuthenticator; import org.apache.commons.mail.Email; import org.apache.commons.mail.EmailException; import org.apache.commons.mail.SimpleEmail; @@ -95,7 +94,7 @@ public void initialize() { } if (!(config.username.isEmpty() || config.password.isEmpty())) { - mail.setAuthenticator(new DefaultAuthenticator(config.username, config.password)); + mail.setAuthentication(config.username, config.password); } Session localSession; @@ -113,7 +112,15 @@ public void initialize() { @Override public void dispose() { - session = null; + Session localSession = session; + if (localSession != null) { + try { + localSession.getTransport().close(); + } catch (MessagingException ignore) { + } + session = null; + } + } /** From 8ab739af93e4c45c4e96724261b6da8d799308df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Thu, 28 Nov 2024 14:47:21 +0100 Subject: [PATCH 4/6] Apply spotless MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël L'hopital --- .../main/java/org/openhab/binding/mail/internal/SMTPHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java index 5cc7736e42c93..5b967ee4472b5 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java @@ -120,7 +120,6 @@ public void dispose() { } session = null; } - } /** From a8a060494bdc921397f30a84ee3841a2bcb212f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Fri, 29 Nov 2024 09:35:27 +0100 Subject: [PATCH 5/6] Better identification of the connexion issue. Sending an email tries to open the connection if it was not opened. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël L'hopital --- .../binding/mail/internal/SMTPHandler.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java index 5b967ee4472b5..86442bab6821a 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java @@ -19,6 +19,7 @@ import javax.activation.DataHandler; import javax.activation.DataSource; import javax.activation.PatchedMailcapCommandMap; +import javax.mail.AuthenticationFailedException; import javax.mail.MessagingException; import javax.mail.Part; import javax.mail.Session; @@ -70,9 +71,18 @@ public void handleCommand(ChannelUID channelUID, Command command) { public void initialize() { updateStatus(ThingStatus.UNKNOWN); + scheduler.execute(this::checkConnection); + } + + private @Nullable Session checkConnection() { + Session localSession = this.session; + if (localSession != null) { + return localSession; + } + SMTPConfig config = getConfigAs(SMTPConfig.class); if (config.sender instanceof String confSender) { - sender = confSender; + this.sender = confSender; } Email mail = new SimpleEmail(); @@ -97,17 +107,20 @@ public void initialize() { mail.setAuthentication(config.username, config.password); } - Session localSession; try { localSession = mail.getMailSession(); localSession.getTransport().connect(); - } catch (EmailException | MessagingException e) { + } catch (AuthenticationFailedException e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage()); - return; + return null; + } catch (EmailException | MessagingException e) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage()); + return null; } this.session = localSession; updateStatus(ThingStatus.ONLINE); + return localSession; } @Override @@ -129,7 +142,7 @@ public void dispose() { * @return true if successful, false if failed */ public boolean sendMail(Email mail) { - Session localSession = session; + Session localSession = checkConnection(); if (localSession == null) { logger.warn("Thing {} is not ONLINE, can't send mail", thing.getUID()); return false; From 536fc674812b6ed296ad6907678c0c3e66d2c551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20L=27hopital?= Date: Fri, 29 Nov 2024 10:39:02 +0100 Subject: [PATCH 6/6] Code cleansing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gaël L'hopital --- .../binding/mail/internal/SMTPHandler.java | 85 +++++++++---------- 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java index 86442bab6821a..5f31ccb4dae42 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/SMTPHandler.java @@ -87,24 +87,22 @@ public void initialize() { Email mail = new SimpleEmail(); mail.setHostName(config.hostname); + if (!(config.username.isEmpty() || config.password.isEmpty())) { + mail.setAuthentication(config.username, config.password); + } int port = config.port != 0 ? config.port : config.security == ServerSecurity.SSL ? 465 : 25; switch (config.security) { - case SSL: + case SSL -> { mail.setSSLOnConnect(true); mail.setSslSmtpPort(Integer.toString(port)); - break; - case STARTTLS: + } + case STARTTLS -> { mail.setStartTLSEnabled(true); mail.setStartTLSRequired(true); mail.setSmtpPort(port); - break; - case PLAIN: - mail.setSmtpPort(port); - } - - if (!(config.username.isEmpty() || config.password.isEmpty())) { - mail.setAuthentication(config.username, config.password); + } + case PLAIN -> mail.setSmtpPort(port); } try { @@ -125,8 +123,7 @@ public void initialize() { @Override public void dispose() { - Session localSession = session; - if (localSession != null) { + if (session instanceof Session localSession) { try { localSession.getTransport().close(); } catch (MessagingException ignore) { @@ -142,47 +139,41 @@ public void dispose() { * @return true if successful, false if failed */ public boolean sendMail(Email mail) { - Session localSession = checkConnection(); - if (localSession == null) { - logger.warn("Thing {} is not ONLINE, can't send mail", thing.getUID()); - return false; - } - - mail.setMailSession(localSession); - - try { - if (mail.getFromAddress() == null && !sender.isEmpty()) { - mail.setFrom(sender); - } else { - logger.warn("No sender defined, can't send mail"); - return false; - } - mail.buildMimeMessage(); + if (checkConnection() instanceof Session localSession) { + mail.setMailSession(localSession); - // fix command map not available - DataHandler dataHandler = mail.getMimeMessage().getDataHandler(); - dataHandler.setCommandMap(commandMap); try { - DataSource dataSource = dataHandler.getDataSource(); - Field dataField = dataSource.getClass().getDeclaredField("data"); - dataField.setAccessible(true); - Object data = dataField.get(dataSource); - if (data instanceof MimeMultipart mimeMultipart) { - for (int i = 0; i < mimeMultipart.getCount(); i++) { - Part mimePart = mimeMultipart.getBodyPart(i); - mimePart.getDataHandler().setCommandMap(commandMap); + if (mail.getFromAddress() == null) { + mail.setFrom(sender); + } + mail.buildMimeMessage(); + + // fix command map not available + DataHandler dataHandler = mail.getMimeMessage().getDataHandler(); + dataHandler.setCommandMap(commandMap); + try { + DataSource dataSource = dataHandler.getDataSource(); + Field dataField = dataSource.getClass().getDeclaredField("data"); + dataField.setAccessible(true); + Object data = dataField.get(dataSource); + if (data instanceof MimeMultipart mimeMultipart) { + for (int i = 0; i < mimeMultipart.getCount(); i++) { + Part mimePart = mimeMultipart.getBodyPart(i); + mimePart.getDataHandler().setCommandMap(commandMap); + } } + } catch (NoSuchFieldException | IllegalAccessException ignored) { } - } catch (NoSuchFieldException | IllegalAccessException ignored) { - } - mail.sendMimeMessage(); - } catch (MessagingException | EmailException e) { - Throwable cause = e.getCause(); - logger.warn("{}", cause != null ? cause.toString() : e.getMessage()); - return false; + mail.sendMimeMessage(); + return true; + } catch (MessagingException | EmailException e) { + logger.warn("{}", e.getCause() instanceof Throwable cause ? cause.toString() : e.getMessage()); + } + } else { + logger.warn("Thing {} is not ONLINE, can't send mail", thing.getUID()); } - return true; + return false; } @Override