From: J-N-K Date: Mon, 3 Jul 2023 07:07:27 +0000 (+0200) Subject: [mail] Add mail content processing (#14345) X-Git-Url: https://git.basschouten.com/?a=commitdiff_plain;h=f0bdeff81b9698318174ea0ee875bdd95d9da7da;p=openhab-addons.git [mail] Add mail content processing (#14345) * [mail] Add mail content processing Signed-off-by: Jan N. Klug --- diff --git a/CODEOWNERS b/CODEOWNERS index c93080812d..c737e7c7ef 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -185,7 +185,7 @@ /bundles/org.openhab.binding.luxom/ @jesperskriasoft /bundles/org.openhab.binding.luxtronikheatpump/ @sgiehl /bundles/org.openhab.binding.magentatv/ @markus7017 -/bundles/org.openhab.binding.mail/ @openhab/add-ons-maintainers +/bundles/org.openhab.binding.mail/ @J-N-K /bundles/org.openhab.binding.max/ @marcelrv /bundles/org.openhab.binding.mcd/ @simon-dengler /bundles/org.openhab.binding.mcp23017/ @aogorek diff --git a/bundles/org.openhab.binding.mail/README.md b/bundles/org.openhab.binding.mail/README.md index 888328440d..21c5ce6d87 100644 --- a/bundles/org.openhab.binding.mail/README.md +++ b/bundles/org.openhab.binding.mail/README.md @@ -40,16 +40,42 @@ Default ports are `143` (for `PLAIN` and `STARTTLS`) and `993` (for `SSL`) in th ## Channels There are no channels for the `smtp` thing. -The `imap` and `pop3` things can be extended with `mailcount`-type channels. +The `imap` and `pop3` things can be extended with `mailcount`- and `content`-type channels. ### Type `mailcount` Each channel has two parameters: `folder` and `type`. + The `folder` is mandatory and denotes the folder name on the given account. -You can either use the root folder like (e.g. "INBOX") or a sub directory of your structure (e.g. "INBOX.Sent" or "INBOX.Junk"). + +You can either use the root folder like (e.g. "INBOX") or a subdirectory of your structure (e.g. "INBOX.Sent" or "INBOX.Junk"). The `type` parameter can be `UNREAD` or `TOTAL` (default). Channels with type `UNREAD` give the number on unread mails in that folder. +### Type `content` + +The `content` type channel presents the contents of an unread mail. +If the message is a MIME- or MIME-multipart message, all parts are concatenated. +The content is converted to a plain string without processing (i.e. HTML tags are still present). +In most cases the mail content needs further processing in rules to trigger appropriate action. + +Each channel has five parameters: `folder`, `subject`, `sender`, `transformation` and `markAsRead`. + +The `folder` is mandatory and denotes the folder name on the given account. +You can either use the root folder like (e.g. "INBOX") or a subdirectory of your structure (e.g. "INBOX.Sent" or "INBOX.Junk"). + +`subject` and `sender` can be used to filter the messages that are processed by the channel. +Filters use regular expressions (e.g. `.*DHL.*` as `sender` would match all From-addresses that contain "DHL"). +If a parameter is left empty, no filter is applied. + +The `transformation` is applied before setting the channel status. +Transformations can be chained by separating them with the mathematical intersection character "∩", e.g. `REGEX:.*Shipment-Status: ([a-z]+).*∩MAP:status.map` would first extract a character string with a regular expression and then apply the given MAP transformation on the result. +Please note that the values will be discarded if one transformation fails (e.g. REGEX did not match). +This means that you can also use it to filter certain emails e.g. `REGEX:(.*Sendungsbenachrichtigung.*)` would only match for mails containing the string "Sendungsbenachrichtigung" but output the whole message. + +Since with each refresh all unread mails are processed the same message content would be sent to the channel multiple times. +This can be prevented by setting `markAsRead` to `true` (default is `false`), which marks all processed messages as read. + ## Full Example mail.things: @@ -61,6 +87,7 @@ Thing mail:imap:sampleimap [ hostname="imap.example.com", security="SSL", userna Channels: Type mailcount : inbox_total [ folder="INBOX", type="TOTAL" ] Type mailcount : inbox_unread [ folder="INBOX", type="UNREAD" ] + Type content : fedex_notification [ folder="INBOX" sender="Fedex.*" markAsRead="true" ] } ``` @@ -69,6 +96,7 @@ mail.items: ```java Number InboxTotal "INBOX [%d]" { channel="mail:imap:sampleimap:inbox_total" } Number InboxUnread "INBOX Unread [%d]" { channel="mail:imap:sampleimap:inbox_unread" } +String FedexNotification { channel="mail:imap:sampleimap:fedex_notification" } ``` mail.sitemap: 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 d81909e2d3..333c3d4462 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 @@ -38,4 +38,5 @@ public class MailBindingConstants { Arrays.asList(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/MailCountChannelType.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailCountChannelType.java index 468914224a..8587b89e57 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailCountChannelType.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailCountChannelType.java @@ -12,12 +12,14 @@ */ package org.openhab.binding.mail.internal; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * The {@link MailCountChannelType} enum for folder mail count type * * @author Jan N. Klug - Initial contribution */ - +@NonNullByDefault public enum MailCountChannelType { UNREAD, TOTAL diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailHandlerFactory.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailHandlerFactory.java index d85b385692..5c54ca5032 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailHandlerFactory.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/MailHandlerFactory.java @@ -29,8 +29,8 @@ import org.osgi.service.component.annotations.Component; * * @author Jan N. Klug - Initial contribution */ -@NonNullByDefault @Component(configurationPid = "binding.mail", service = ThingHandlerFactory.class) +@NonNullByDefault public class MailHandlerFactory extends BaseThingHandlerFactory { @Override diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/POP3IMAPHandler.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/POP3IMAPHandler.java index 03a03292fd..e92ef18782 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/POP3IMAPHandler.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/POP3IMAPHandler.java @@ -13,29 +13,41 @@ package org.openhab.binding.mail.internal; import static org.openhab.binding.mail.internal.MailBindingConstants.CHANNEL_TYPE_UID_FOLDER_MAILCOUNT; +import static org.openhab.binding.mail.internal.MailBindingConstants.CHANNEL_TYPE_UID_MAIL_CONTENT; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.Properties; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.mail.Address; import javax.mail.Flags; import javax.mail.Folder; +import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.Store; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; import javax.mail.search.FlagTerm; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.mail.internal.config.POP3IMAPChannelConfig; import org.openhab.binding.mail.internal.config.POP3IMAPConfig; +import org.openhab.binding.mail.internal.config.POP3IMAPContentChannelConfig; +import org.openhab.binding.mail.internal.config.POP3IMAPMailCountChannelConfig; import org.openhab.core.library.types.DecimalType; +import org.openhab.core.library.types.StringType; import org.openhab.core.thing.Channel; 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.generic.ChannelTransformation; import org.openhab.core.types.Command; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,21 +88,14 @@ public class POP3IMAPHandler extends BaseThingHandler { if (config.port == 0) { switch (protocol) { - case "imap": - config.port = 143; - break; - case "imaps": - config.port = 993; - break; - case "pop3": - config.port = 110; - break; - case "pop3s": - config.port = 995; - break; - default: + case "imap" -> config.port = 143; + case "imaps" -> config.port = 993; + case "pop3" -> config.port = 110; + case "pop3s" -> config.port = 995; + default -> { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR); return; + } } } @@ -109,6 +114,9 @@ public class POP3IMAPHandler extends BaseThingHandler { } private void refresh() { + if (Thread.currentThread().isInterrupted()) { + return; + } Properties props = new Properties(); props.setProperty("mail." + baseProtocol + ".starttls.enable", "true"); props.setProperty("mail.store.protocol", protocol); @@ -119,8 +127,8 @@ public class POP3IMAPHandler extends BaseThingHandler { for (Channel channel : thing.getChannels()) { if (CHANNEL_TYPE_UID_FOLDER_MAILCOUNT.equals(channel.getChannelTypeUID())) { - final POP3IMAPChannelConfig channelConfig = channel.getConfiguration() - .as(POP3IMAPChannelConfig.class); + final POP3IMAPMailCountChannelConfig channelConfig = channel.getConfiguration() + .as(POP3IMAPMailCountChannelConfig.class); final String folderName = channelConfig.folder; if (folderName == null || folderName.isEmpty()) { logger.info("missing or empty folder name in channel {}", channel.getUID()); @@ -133,14 +141,65 @@ public class POP3IMAPHandler extends BaseThingHandler { updateState(channel.getUID(), new DecimalType( mailbox.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false)).length)); } - } catch (MessagingException e) { - throw e; + } + } + } else if (CHANNEL_TYPE_UID_MAIL_CONTENT.equals(channel.getChannelTypeUID())) { + final POP3IMAPContentChannelConfig channelConfig = channel.getConfiguration() + .as(POP3IMAPContentChannelConfig.class); + final String folderName = channelConfig.folder; + if (folderName == null || folderName.isEmpty()) { + logger.info("missing or empty folder name in channel '{}'", channel.getUID()); + } else { + try (Folder mailbox = store.getFolder(folderName)) { + mailbox.open(channelConfig.markAsRead ? Folder.READ_WRITE : Folder.READ_ONLY); + Message[] messages = mailbox.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false)); + for (Message message : messages) { + String subject = message.getSubject(); + Address[] senders = message.getFrom(); + String sender = senders == null ? "" + : Stream.of(senders).map(Address::toString).collect(Collectors.joining(",")); + logger.debug("Processing `{}` from `{}`", subject, sender); + if (!channelConfig.subject.isBlank() && !subject.matches(channelConfig.subject)) { + logger.trace("Subject '{}' did not pass subject filter", subject); + continue; + } + if (!channelConfig.sender.isBlank() && !sender.matches(channelConfig.sender)) { + logger.trace("Sender '{}' did not pass filter '{}'", subject, channelConfig.sender); + continue; + } + Object rawContent = message.getContent(); + String contentAsString; + if (rawContent instanceof String) { + logger.trace("Detected plain text message"); + contentAsString = (String) rawContent; + } else if (rawContent instanceof MimeMessage mimeMessage) { + logger.trace("Detected MIME message"); + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + mimeMessage.writeTo(os); + contentAsString = os.toString(); + } + } else if (rawContent instanceof MimeMultipart mimeMultipart) { + logger.trace("Detected MIME multipart message"); + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + mimeMultipart.writeTo(os); + contentAsString = os.toString(); + } + } else { + logger.warn( + "Failed to convert mail content from '{}' with subject '{}', to String: {}", + sender, subject, rawContent.getClass()); + continue; + } + logger.trace("Found content '{}'", contentAsString); + new ChannelTransformation(channelConfig.transformation).apply(contentAsString) + .ifPresent(result -> updateState(channel.getUID(), new StringType(result))); + } } } } } - } catch (MessagingException e) { - logger.info("error when trying to refresh IMAP: {}", e.getMessage()); + } catch (MessagingException | IOException e) { + logger.info("Failed refreshing IMAP for thing '{}': {}", thing.getUID(), e.getMessage()); } } } diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/ServerSecurity.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/ServerSecurity.java index f919f98728..a7ec050b60 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/ServerSecurity.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/ServerSecurity.java @@ -12,12 +12,14 @@ */ package org.openhab.binding.mail.internal; +import org.eclipse.jdt.annotation.NonNullByDefault; + /** * The {@link ServerSecurity} enum contains security configuration options * * @author Jan N. Klug - Initial contribution */ - +@NonNullByDefault public enum ServerSecurity { PLAIN, SSL, 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 246251624e..2970b77040 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 @@ -21,7 +21,6 @@ import org.openhab.binding.mail.internal.ServerSecurity; * * @author Jan N. Klug - Initial contribution */ - @NonNullByDefault public class BaseConfig { public @Nullable String hostname; diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPChannelConfig.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPChannelConfig.java deleted file mode 100644 index 727172f234..0000000000 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPChannelConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2010-2023 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.mail.internal.config; - -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; -import org.openhab.binding.mail.internal.MailCountChannelType; - -/** - * The {@link POP3IMAPChannelConfig} class contains fields mapping thing configuration parameters. - * - * @author Jan N. Klug - Initial contribution - */ - -@NonNullByDefault -public class POP3IMAPChannelConfig { - public @Nullable String folder; - public MailCountChannelType type = MailCountChannelType.TOTAL; -} diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPConfig.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPConfig.java index dbc43a913f..9527807c68 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPConfig.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPConfig.java @@ -19,7 +19,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault; * * @author Jan N. Klug - Initial contribution */ - @NonNullByDefault public class POP3IMAPConfig extends BaseConfig { public int refresh = 60; diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPContentChannelConfig.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPContentChannelConfig.java new file mode 100644 index 0000000000..cbddc9c6d6 --- /dev/null +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPContentChannelConfig.java @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.mail.internal.config; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; + +/** + * The {@link POP3IMAPContentChannelConfig} class contains fields mapping thing configuration parameters. + * + * @author Jan N. Klug - Initial contribution + */ +@NonNullByDefault +public class POP3IMAPContentChannelConfig { + public @Nullable String folder; + public String subject = ""; + public String sender = ""; + public @Nullable String transformation; + + public boolean markAsRead = false; +} diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPMailCountChannelConfig.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPMailCountChannelConfig.java new file mode 100644 index 0000000000..89906fe806 --- /dev/null +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/POP3IMAPMailCountChannelConfig.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.mail.internal.config; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.mail.internal.MailCountChannelType; + +/** + * The {@link POP3IMAPMailCountChannelConfig} class contains fields mapping thing configuration parameters. + * + * @author Jan N. Klug - Initial contribution + */ +@NonNullByDefault +public class POP3IMAPMailCountChannelConfig { + public @Nullable String folder; + public MailCountChannelType type = MailCountChannelType.TOTAL; +} diff --git a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/SMTPConfig.java b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/SMTPConfig.java index 4bef43bbce..a68029476d 100644 --- a/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/SMTPConfig.java +++ b/bundles/org.openhab.binding.mail/src/main/java/org/openhab/binding/mail/internal/config/SMTPConfig.java @@ -20,7 +20,6 @@ import org.eclipse.jdt.annotation.Nullable; * * @author Jan N. Klug - Initial contribution */ - @NonNullByDefault public class SMTPConfig extends BaseConfig { public @Nullable String sender; diff --git a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail.properties b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail.properties index 9deedf1b20..2a8b1251cf 100644 --- a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail.properties +++ b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/i18n/mail.properties @@ -20,29 +20,42 @@ thing-type.config.mail.smtp.port.description = Default values are 25 for plain/S thing-type.config.mail.smtp.sender.label = Sender thing-type.config.mail.smtp.sender.description = Default sender address for mail -config.hostname.label = Server Hostname -config.password.label = SMTP Server Password -config.port.label = Server Port -config.refresh.label = Refresh Time -config.refresh.description = Refresh time for this account in seconds -config.security.label = SMTP Server Security Protocol -config.security.option.PLAIN = plain -config.security.option.STARTTLS = STARTTLS -config.security.option.SSL = SSL/TLS -config.username.label = SMTP Server Username - # channel types +channel-type.mail.content.label = Content +channel-type.mail.content.description = Mail content as String (with subject filter and content transformation). channel-type.mail.mailcount.label = Mail Count channel-type.mail.mailcount.description = Number of emails in folder # channel types config +channel-type.config.mail.content.folder.label = Folder Name +channel-type.config.mail.content.markAsRead.label = Mark As Read +channel-type.config.mail.content.markAsRead.description = Mark a processed mail as read and prevent further processing. +channel-type.config.mail.content.sender.label = Sender Filter +channel-type.config.mail.content.sender.description = A (regular expression) filter for the mail sender address. +channel-type.config.mail.content.subject.label = Subject Filter +channel-type.config.mail.content.subject.description = A (regular expression) filter for the mail subject. +channel-type.config.mail.content.transformation.label = Transformation +channel-type.config.mail.content.transformation.description = Transformation pattern used when processing messages. Multiple transformation can be chained using "∩". channel-type.config.mail.mailcount.folder.label = Folder Name channel-type.config.mail.mailcount.type.label = Counter Type channel-type.config.mail.mailcount.type.option.UNREAD = Unread channel-type.config.mail.mailcount.type.option.TOTAL = Total +# thing types config + +config.hostname.label = Server Hostname +config.password.label = SMTP Server Password +config.port.label = Server Port +config.refresh.label = Refresh Time +config.refresh.description = Refresh time for this account in seconds +config.security.label = SMTP Server Security Protocol +config.security.option.PLAIN = plain +config.security.option.STARTTLS = STARTTLS +config.security.option.SSL = SSL/TLS +config.username.label = SMTP Server Username + # actions addHeaderActionLabel = add a mail header diff --git a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/thing/thing-types.xml index 5483caecb2..dd68b3519a 100644 --- a/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.mail/src/main/resources/OH-INF/thing/thing-types.xml @@ -15,12 +15,12 @@ - + Default values are 25 for plain/STARTTLS and 465 for SSL/TLS true - + @@ -30,28 +30,28 @@ true PLAIN - + - + password - + Used for receiving emails - + Default values are 143 for plain/STARTTLS and 993 for SSL/TLS true - + @@ -68,26 +68,26 @@ password - + @text/config.refresh.description 60 - + Used for receiving emails - + Default values are 110 for plain/STARTTLS and 995 for SSL/TLS true - + @@ -104,7 +104,7 @@ password - + @text/config.refresh.description 60 @@ -121,7 +121,7 @@ - + @@ -132,4 +132,33 @@ + + + String + + Mail content as String (with subject filter and content transformation). + + + + + + + + A (regular expression) filter for the mail subject. + + + + A (regular expression) filter for the mail sender address. + + + + Transformation pattern used when processing messages. Multiple transformation can be chained using "∩". + + + + Mark a processed mail as read and prevent further processing. + false + + + diff --git a/bundles/org.openhab.binding.mail/src/test/java/org/openhab/binding/mail/MailBuilderTest.java b/bundles/org.openhab.binding.mail/src/test/java/org/openhab/binding/mail/MailBuilderTest.java deleted file mode 100644 index 542d138eb1..0000000000 --- a/bundles/org.openhab.binding.mail/src/test/java/org/openhab/binding/mail/MailBuilderTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2010-2023 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.mail; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.*; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.nio.file.Path; -import java.util.Map; - -import javax.mail.MessagingException; -import javax.mail.internet.AddressException; - -import org.apache.commons.mail.Email; -import org.apache.commons.mail.EmailException; -import org.apache.commons.mail.HtmlEmail; -import org.apache.commons.mail.MultiPartEmail; -import org.apache.commons.mail.SimpleEmail; -import org.junit.jupiter.api.Test; -import org.openhab.binding.mail.internal.MailBuilder; - -/** - * The {@link MailBuilderTest} class defines tests for the {@link MailBuilder} class - * - * @author Jan N. Klug - Initial contribution - */ - -public class MailBuilderTest { - - private static final String TEST_STRING = "test"; - private static final String TEST_EMAIL = "foo@bar.zinga"; - - private static final String HEADER_1_KEY = "key_one"; - private static final String HEADER_1_VAL = "value_one"; - private static final String HEADER_2_KEY = "key_two"; - private static final String HEADER_2_VAL = "value_two"; - - @Test - public void illegalToAddressThrowsException() { - assertThrows(AddressException.class, () -> new MailBuilder("foo bar.zinga")); - } - - @Test - public void illegalFromAddressThrowsException() { - assertThrows(EmailException.class, () -> new MailBuilder("TEST_EMAIL").withSender("foo bar.zinga").build()); - } - - @Test - public void illegalURLThrowsException() { - assertThrows(MalformedURLException.class, - () -> new MailBuilder("TEST_EMAIL").withURLAttachment("foo bar.zinga")); - } - - @Test - public void withTextOnlyReturnsSimpleEmail() throws AddressException, EmailException { - MailBuilder builder = new MailBuilder(TEST_EMAIL); - Email mail = builder.withText("boo").build(); - assertThat(mail, instanceOf(SimpleEmail.class)); - } - - @Test - public void withURLAttachmentReturnsMultiPartEmail() - throws AddressException, EmailException, MalformedURLException { - MailBuilder builder = new MailBuilder(TEST_EMAIL); - String url = Path.of("src/test/resources/attachment.txt").toUri().toURL().toString(); - Email mail = builder.withText("boo").withURLAttachment(url).build(); - assertThat(mail, instanceOf(MultiPartEmail.class)); - } - - @Test - public void withHtmlReturnsHtmlEmail() throws AddressException, EmailException { - MailBuilder builder = new MailBuilder(TEST_EMAIL); - Email mail = builder.withHtml("test").build(); - assertThat(mail, instanceOf(HtmlEmail.class)); - } - - @Test - public void fieldsSetInMail() throws EmailException, MessagingException, IOException { - MailBuilder builder = new MailBuilder(TEST_EMAIL); - - assertEquals("(no subject)", builder.build().getSubject()); - assertEquals(TEST_STRING, builder.withSubject(TEST_STRING).build().getSubject()); - - assertEquals(TEST_EMAIL, builder.withSender(TEST_EMAIL).build().getFromAddress().getAddress()); - - assertEquals(TEST_EMAIL, builder.build().getToAddresses().get(0).getAddress()); - assertEquals(2, builder.withRecipients(TEST_EMAIL).build().getToAddresses().size()); - } - - @Test - public void withHeaders() throws EmailException, MessagingException, IOException { - MailBuilder builder = new MailBuilder(TEST_EMAIL); - Email mail = builder.withHeader(HEADER_1_KEY, HEADER_1_VAL).withHeader(HEADER_2_KEY, HEADER_2_VAL).build(); - - Map headers = mail.getHeaders(); - - assertEquals(2, headers.size()); - assertEquals(HEADER_2_VAL, headers.get(HEADER_2_KEY)); - assertEquals(HEADER_1_VAL, headers.get(HEADER_1_KEY)); - } -} diff --git a/bundles/org.openhab.binding.mail/src/test/java/org/openhab/binding/mail/internal/MailBuilderTest.java b/bundles/org.openhab.binding.mail/src/test/java/org/openhab/binding/mail/internal/MailBuilderTest.java new file mode 100644 index 0000000000..03fdf636c0 --- /dev/null +++ b/bundles/org.openhab.binding.mail/src/test/java/org/openhab/binding/mail/internal/MailBuilderTest.java @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.mail.internal; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.file.Path; +import java.util.Map; + +import javax.mail.MessagingException; +import javax.mail.internet.AddressException; + +import org.apache.commons.mail.Email; +import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.HtmlEmail; +import org.apache.commons.mail.MultiPartEmail; +import org.apache.commons.mail.SimpleEmail; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; + +/** + * The {@link MailBuilderTest} class defines tests for the {@link MailBuilder} class + * + * @author Jan N. Klug - Initial contribution + */ +@NonNullByDefault +public class MailBuilderTest { + + private static final String TEST_STRING = "test"; + private static final String TEST_EMAIL = "foo@bar.zinga"; + + private static final String HEADER_1_KEY = "key_one"; + private static final String HEADER_1_VAL = "value_one"; + private static final String HEADER_2_KEY = "key_two"; + private static final String HEADER_2_VAL = "value_two"; + + @Test + public void illegalToAddressThrowsException() { + assertThrows(AddressException.class, () -> new MailBuilder("foo bar.zinga")); + } + + @Test + public void illegalFromAddressThrowsException() { + assertThrows(EmailException.class, () -> new MailBuilder("TEST_EMAIL").withSender("foo bar.zinga").build()); + } + + @Test + public void illegalURLThrowsException() { + assertThrows(MalformedURLException.class, + () -> new MailBuilder("TEST_EMAIL").withURLAttachment("foo bar.zinga")); + } + + @Test + public void withTextOnlyReturnsSimpleEmail() throws AddressException, EmailException { + MailBuilder builder = new MailBuilder(TEST_EMAIL); + Email mail = builder.withText("boo").build(); + assertThat(mail, instanceOf(SimpleEmail.class)); + } + + @Test + public void withURLAttachmentReturnsMultiPartEmail() + throws AddressException, EmailException, MalformedURLException { + MailBuilder builder = new MailBuilder(TEST_EMAIL); + String url = Path.of("src/test/resources/attachment.txt").toUri().toURL().toString(); + Email mail = builder.withText("boo").withURLAttachment(url).build(); + assertThat(mail, instanceOf(MultiPartEmail.class)); + } + + @Test + public void withHtmlReturnsHtmlEmail() throws AddressException, EmailException { + MailBuilder builder = new MailBuilder(TEST_EMAIL); + Email mail = builder.withHtml("test").build(); + assertThat(mail, instanceOf(HtmlEmail.class)); + } + + @Test + public void fieldsSetInMail() throws EmailException, MessagingException, IOException { + MailBuilder builder = new MailBuilder(TEST_EMAIL); + + assertEquals("(no subject)", builder.build().getSubject()); + assertEquals(TEST_STRING, builder.withSubject(TEST_STRING).build().getSubject()); + + assertEquals(TEST_EMAIL, builder.withSender(TEST_EMAIL).build().getFromAddress().getAddress()); + + assertEquals(TEST_EMAIL, builder.build().getToAddresses().get(0).getAddress()); + assertEquals(2, builder.withRecipients(TEST_EMAIL).build().getToAddresses().size()); + } + + @Test + public void withHeaders() throws EmailException, MessagingException, IOException { + MailBuilder builder = new MailBuilder(TEST_EMAIL); + Email mail = builder.withHeader(HEADER_1_KEY, HEADER_1_VAL).withHeader(HEADER_2_KEY, HEADER_2_VAL).build(); + + Map headers = mail.getHeaders(); + + assertEquals(2, headers.size()); + assertEquals(HEADER_2_VAL, headers.get(HEADER_2_KEY)); + assertEquals(HEADER_1_VAL, headers.get(HEADER_1_KEY)); + } +} diff --git a/tools/static-code-analysis/checkstyle/suppressions.xml b/tools/static-code-analysis/checkstyle/suppressions.xml index 6574121b9e..82b5297c23 100644 --- a/tools/static-code-analysis/checkstyle/suppressions.xml +++ b/tools/static-code-analysis/checkstyle/suppressions.xml @@ -22,4 +22,9 @@ + + + + +