mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[mail] Add mail content processing (#14345)
* [mail] Add mail content processing Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
parent
99e78d84b5
commit
f0bdeff81b
@ -185,7 +185,7 @@
|
|||||||
/bundles/org.openhab.binding.luxom/ @jesperskriasoft
|
/bundles/org.openhab.binding.luxom/ @jesperskriasoft
|
||||||
/bundles/org.openhab.binding.luxtronikheatpump/ @sgiehl
|
/bundles/org.openhab.binding.luxtronikheatpump/ @sgiehl
|
||||||
/bundles/org.openhab.binding.magentatv/ @markus7017
|
/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.max/ @marcelrv
|
||||||
/bundles/org.openhab.binding.mcd/ @simon-dengler
|
/bundles/org.openhab.binding.mcd/ @simon-dengler
|
||||||
/bundles/org.openhab.binding.mcp23017/ @aogorek
|
/bundles/org.openhab.binding.mcp23017/ @aogorek
|
||||||
|
@ -40,16 +40,42 @@ Default ports are `143` (for `PLAIN` and `STARTTLS`) and `993` (for `SSL`) in th
|
|||||||
## Channels
|
## Channels
|
||||||
|
|
||||||
There are no channels for the `smtp` thing.
|
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`
|
### Type `mailcount`
|
||||||
|
|
||||||
Each channel has two parameters: `folder` and `type`.
|
Each channel has two parameters: `folder` and `type`.
|
||||||
|
|
||||||
The `folder` is mandatory and denotes the folder name on the given account.
|
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).
|
The `type` parameter can be `UNREAD` or `TOTAL` (default).
|
||||||
Channels with type `UNREAD` give the number on unread mails in that folder.
|
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
|
## Full Example
|
||||||
|
|
||||||
mail.things:
|
mail.things:
|
||||||
@ -61,6 +87,7 @@ Thing mail:imap:sampleimap [ hostname="imap.example.com", security="SSL", userna
|
|||||||
Channels:
|
Channels:
|
||||||
Type mailcount : inbox_total [ folder="INBOX", type="TOTAL" ]
|
Type mailcount : inbox_total [ folder="INBOX", type="TOTAL" ]
|
||||||
Type mailcount : inbox_unread [ folder="INBOX", type="UNREAD" ]
|
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
|
```java
|
||||||
Number InboxTotal "INBOX [%d]" { channel="mail:imap:sampleimap:inbox_total" }
|
Number InboxTotal "INBOX [%d]" { channel="mail:imap:sampleimap:inbox_total" }
|
||||||
Number InboxUnread "INBOX Unread [%d]" { channel="mail:imap:sampleimap:inbox_unread" }
|
Number InboxUnread "INBOX Unread [%d]" { channel="mail:imap:sampleimap:inbox_unread" }
|
||||||
|
String FedexNotification { channel="mail:imap:sampleimap:fedex_notification" }
|
||||||
```
|
```
|
||||||
|
|
||||||
mail.sitemap:
|
mail.sitemap:
|
||||||
|
@ -38,4 +38,5 @@ public class MailBindingConstants {
|
|||||||
Arrays.asList(THING_TYPE_SMTPSERVER, THING_TYPE_IMAPSERVER, THING_TYPE_POP3SERVER));
|
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_FOLDER_MAILCOUNT = new ChannelTypeUID(BINDING_ID, "mailcount");
|
||||||
|
public static final ChannelTypeUID CHANNEL_TYPE_UID_MAIL_CONTENT = new ChannelTypeUID(BINDING_ID, "content");
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mail.internal;
|
package org.openhab.binding.mail.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MailCountChannelType} enum for folder mail count type
|
* The {@link MailCountChannelType} enum for folder mail count type
|
||||||
*
|
*
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public enum MailCountChannelType {
|
public enum MailCountChannelType {
|
||||||
UNREAD,
|
UNREAD,
|
||||||
TOTAL
|
TOTAL
|
||||||
|
@ -29,8 +29,8 @@ import org.osgi.service.component.annotations.Component;
|
|||||||
*
|
*
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
|
||||||
@Component(configurationPid = "binding.mail", service = ThingHandlerFactory.class)
|
@Component(configurationPid = "binding.mail", service = ThingHandlerFactory.class)
|
||||||
|
@NonNullByDefault
|
||||||
public class MailHandlerFactory extends BaseThingHandlerFactory {
|
public class MailHandlerFactory extends BaseThingHandlerFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -13,29 +13,41 @@
|
|||||||
package org.openhab.binding.mail.internal;
|
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_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.Properties;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
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.Flags;
|
||||||
import javax.mail.Folder;
|
import javax.mail.Folder;
|
||||||
|
import javax.mail.Message;
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
import javax.mail.Session;
|
import javax.mail.Session;
|
||||||
import javax.mail.Store;
|
import javax.mail.Store;
|
||||||
|
import javax.mail.internet.MimeMessage;
|
||||||
|
import javax.mail.internet.MimeMultipart;
|
||||||
import javax.mail.search.FlagTerm;
|
import javax.mail.search.FlagTerm;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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.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.DecimalType;
|
||||||
|
import org.openhab.core.library.types.StringType;
|
||||||
import org.openhab.core.thing.Channel;
|
import org.openhab.core.thing.Channel;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
import org.openhab.core.thing.ThingStatusDetail;
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||||
|
import org.openhab.core.thing.binding.generic.ChannelTransformation;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -76,21 +88,14 @@ public class POP3IMAPHandler extends BaseThingHandler {
|
|||||||
|
|
||||||
if (config.port == 0) {
|
if (config.port == 0) {
|
||||||
switch (protocol) {
|
switch (protocol) {
|
||||||
case "imap":
|
case "imap" -> config.port = 143;
|
||||||
config.port = 143;
|
case "imaps" -> config.port = 993;
|
||||||
break;
|
case "pop3" -> config.port = 110;
|
||||||
case "imaps":
|
case "pop3s" -> config.port = 995;
|
||||||
config.port = 993;
|
default -> {
|
||||||
break;
|
|
||||||
case "pop3":
|
|
||||||
config.port = 110;
|
|
||||||
break;
|
|
||||||
case "pop3s":
|
|
||||||
config.port = 995;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +114,9 @@ public class POP3IMAPHandler extends BaseThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void refresh() {
|
private void refresh() {
|
||||||
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty("mail." + baseProtocol + ".starttls.enable", "true");
|
props.setProperty("mail." + baseProtocol + ".starttls.enable", "true");
|
||||||
props.setProperty("mail.store.protocol", protocol);
|
props.setProperty("mail.store.protocol", protocol);
|
||||||
@ -119,8 +127,8 @@ public class POP3IMAPHandler extends BaseThingHandler {
|
|||||||
|
|
||||||
for (Channel channel : thing.getChannels()) {
|
for (Channel channel : thing.getChannels()) {
|
||||||
if (CHANNEL_TYPE_UID_FOLDER_MAILCOUNT.equals(channel.getChannelTypeUID())) {
|
if (CHANNEL_TYPE_UID_FOLDER_MAILCOUNT.equals(channel.getChannelTypeUID())) {
|
||||||
final POP3IMAPChannelConfig channelConfig = channel.getConfiguration()
|
final POP3IMAPMailCountChannelConfig channelConfig = channel.getConfiguration()
|
||||||
.as(POP3IMAPChannelConfig.class);
|
.as(POP3IMAPMailCountChannelConfig.class);
|
||||||
final String folderName = channelConfig.folder;
|
final String folderName = channelConfig.folder;
|
||||||
if (folderName == null || folderName.isEmpty()) {
|
if (folderName == null || folderName.isEmpty()) {
|
||||||
logger.info("missing or empty folder name in channel {}", channel.getUID());
|
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(
|
updateState(channel.getUID(), new DecimalType(
|
||||||
mailbox.search(new FlagTerm(new Flags(Flags.Flag.SEEN), false)).length));
|
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) {
|
} catch (MessagingException | IOException e) {
|
||||||
logger.info("error when trying to refresh IMAP: {}", e.getMessage());
|
logger.info("Failed refreshing IMAP for thing '{}': {}", thing.getUID(), e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.mail.internal;
|
package org.openhab.binding.mail.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link ServerSecurity} enum contains security configuration options
|
* The {@link ServerSecurity} enum contains security configuration options
|
||||||
*
|
*
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public enum ServerSecurity {
|
public enum ServerSecurity {
|
||||||
PLAIN,
|
PLAIN,
|
||||||
SSL,
|
SSL,
|
||||||
|
@ -21,7 +21,6 @@ import org.openhab.binding.mail.internal.ServerSecurity;
|
|||||||
*
|
*
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class BaseConfig {
|
public class BaseConfig {
|
||||||
public @Nullable String hostname;
|
public @Nullable String hostname;
|
||||||
|
@ -19,7 +19,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||||||
*
|
*
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class POP3IMAPConfig extends BaseConfig {
|
public class POP3IMAPConfig extends BaseConfig {
|
||||||
public int refresh = 60;
|
public int refresh = 60;
|
||||||
|
@ -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;
|
||||||
|
}
|
@ -17,13 +17,12 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||||||
import org.openhab.binding.mail.internal.MailCountChannelType;
|
import org.openhab.binding.mail.internal.MailCountChannelType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link POP3IMAPChannelConfig} class contains fields mapping thing configuration parameters.
|
* The {@link POP3IMAPMailCountChannelConfig} class contains fields mapping thing configuration parameters.
|
||||||
*
|
*
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class POP3IMAPChannelConfig {
|
public class POP3IMAPMailCountChannelConfig {
|
||||||
public @Nullable String folder;
|
public @Nullable String folder;
|
||||||
public MailCountChannelType type = MailCountChannelType.TOTAL;
|
public MailCountChannelType type = MailCountChannelType.TOTAL;
|
||||||
}
|
}
|
@ -20,7 +20,6 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||||||
*
|
*
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class SMTPConfig extends BaseConfig {
|
public class SMTPConfig extends BaseConfig {
|
||||||
public @Nullable String sender;
|
public @Nullable String sender;
|
||||||
|
@ -20,6 +20,31 @@ 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.label = Sender
|
||||||
thing-type.config.mail.smtp.sender.description = Default sender address for mail
|
thing-type.config.mail.smtp.sender.description = Default sender address for mail
|
||||||
|
|
||||||
|
# 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.hostname.label = Server Hostname
|
||||||
config.password.label = SMTP Server Password
|
config.password.label = SMTP Server Password
|
||||||
config.port.label = Server Port
|
config.port.label = Server Port
|
||||||
@ -31,18 +56,6 @@ config.security.option.STARTTLS = STARTTLS
|
|||||||
config.security.option.SSL = SSL/TLS
|
config.security.option.SSL = SSL/TLS
|
||||||
config.username.label = SMTP Server Username
|
config.username.label = SMTP Server Username
|
||||||
|
|
||||||
# channel types
|
|
||||||
|
|
||||||
channel-type.mail.mailcount.label = Mail Count
|
|
||||||
channel-type.mail.mailcount.description = Number of emails in folder
|
|
||||||
|
|
||||||
# channel types config
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# actions
|
# actions
|
||||||
|
|
||||||
addHeaderActionLabel = add a mail header
|
addHeaderActionLabel = add a mail header
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
<parameter name="hostname" type="text" required="true">
|
<parameter name="hostname" type="text" required="true">
|
||||||
<label>@text/config.hostname.label</label>
|
<label>@text/config.hostname.label</label>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="port" type="text" required="false">
|
<parameter name="port" type="text">
|
||||||
<label>@text/config.port.label</label>
|
<label>@text/config.port.label</label>
|
||||||
<description>Default values are 25 for plain/STARTTLS and 465 for SSL/TLS</description>
|
<description>Default values are 25 for plain/STARTTLS and 465 for SSL/TLS</description>
|
||||||
<advanced>true</advanced>
|
<advanced>true</advanced>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="security" type="text" required="false">
|
<parameter name="security" type="text">
|
||||||
<label>@text/config.security.label</label>
|
<label>@text/config.security.label</label>
|
||||||
<options>
|
<options>
|
||||||
<option value="PLAIN">@text/config.security.option.PLAIN</option>
|
<option value="PLAIN">@text/config.security.option.PLAIN</option>
|
||||||
@ -30,28 +30,28 @@
|
|||||||
<limitToOptions>true</limitToOptions>
|
<limitToOptions>true</limitToOptions>
|
||||||
<default>PLAIN</default>
|
<default>PLAIN</default>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="username" type="text" required="false">
|
<parameter name="username" type="text">
|
||||||
<label>@text/config.username.label</label>
|
<label>@text/config.username.label</label>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="password" type="text" required="false">
|
<parameter name="password" type="text">
|
||||||
<label>@text/config.password.label</label>
|
<label>@text/config.password.label</label>
|
||||||
<context>password</context>
|
<context>password</context>
|
||||||
</parameter>
|
</parameter>
|
||||||
</config-description>
|
</config-description>
|
||||||
</thing-type>
|
</thing-type>
|
||||||
<thing-type id="imap" extensible="mailcount">
|
<thing-type id="imap" extensible="mailcount,content">
|
||||||
<label>IMAP Server</label>
|
<label>IMAP Server</label>
|
||||||
<description>Used for receiving emails</description>
|
<description>Used for receiving emails</description>
|
||||||
<config-description>
|
<config-description>
|
||||||
<parameter name="hostname" type="text" required="true">
|
<parameter name="hostname" type="text" required="true">
|
||||||
<label>@text/config.hostname.label</label>
|
<label>@text/config.hostname.label</label>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="port" type="text" required="false">
|
<parameter name="port" type="text">
|
||||||
<label>@text/config.port.label</label>
|
<label>@text/config.port.label</label>
|
||||||
<description>Default values are 143 for plain/STARTTLS and 993 for SSL/TLS</description>
|
<description>Default values are 143 for plain/STARTTLS and 993 for SSL/TLS</description>
|
||||||
<advanced>true</advanced>
|
<advanced>true</advanced>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="security" type="text" required="false">
|
<parameter name="security" type="text">
|
||||||
<label>@text/config.security.label</label>
|
<label>@text/config.security.label</label>
|
||||||
<options>
|
<options>
|
||||||
<option value="PLAIN">@text/config.security.option.PLAIN</option>
|
<option value="PLAIN">@text/config.security.option.PLAIN</option>
|
||||||
@ -68,26 +68,26 @@
|
|||||||
<label>@text/config.password.label</label>
|
<label>@text/config.password.label</label>
|
||||||
<context>password</context>
|
<context>password</context>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="refresh" type="integer" required="false">
|
<parameter name="refresh" type="integer">
|
||||||
<label>@text/config.refresh.label</label>
|
<label>@text/config.refresh.label</label>
|
||||||
<description>@text/config.refresh.description</description>
|
<description>@text/config.refresh.description</description>
|
||||||
<default>60</default>
|
<default>60</default>
|
||||||
</parameter>
|
</parameter>
|
||||||
</config-description>
|
</config-description>
|
||||||
</thing-type>
|
</thing-type>
|
||||||
<thing-type id="pop3" extensible="mailcount">
|
<thing-type id="pop3" extensible="mailcount,content">
|
||||||
<label>POP3 Server</label>
|
<label>POP3 Server</label>
|
||||||
<description>Used for receiving emails</description>
|
<description>Used for receiving emails</description>
|
||||||
<config-description>
|
<config-description>
|
||||||
<parameter name="hostname" type="text" required="true">
|
<parameter name="hostname" type="text" required="true">
|
||||||
<label>@text/config.hostname.label</label>
|
<label>@text/config.hostname.label</label>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="port" type="text" required="false">
|
<parameter name="port" type="text">
|
||||||
<label>@text/config.port.label</label>
|
<label>@text/config.port.label</label>
|
||||||
<description>Default values are 110 for plain/STARTTLS and 995 for SSL/TLS</description>
|
<description>Default values are 110 for plain/STARTTLS and 995 for SSL/TLS</description>
|
||||||
<advanced>true</advanced>
|
<advanced>true</advanced>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="security" type="text" required="false">
|
<parameter name="security" type="text">
|
||||||
<label>@text/config.security.label</label>
|
<label>@text/config.security.label</label>
|
||||||
<options>
|
<options>
|
||||||
<option value="PLAIN">@text/config.security.option.PLAIN</option>
|
<option value="PLAIN">@text/config.security.option.PLAIN</option>
|
||||||
@ -104,7 +104,7 @@
|
|||||||
<label>@text/config.password.label</label>
|
<label>@text/config.password.label</label>
|
||||||
<context>password</context>
|
<context>password</context>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="refresh" type="integer" required="false">
|
<parameter name="refresh" type="integer">
|
||||||
<label>@text/config.refresh.label</label>
|
<label>@text/config.refresh.label</label>
|
||||||
<description>@text/config.refresh.description</description>
|
<description>@text/config.refresh.description</description>
|
||||||
<default>60</default>
|
<default>60</default>
|
||||||
@ -121,7 +121,7 @@
|
|||||||
<parameter name="folder" type="text" required="true">
|
<parameter name="folder" type="text" required="true">
|
||||||
<label>Folder Name</label>
|
<label>Folder Name</label>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="type" type="text" required="false">
|
<parameter name="type" type="text">
|
||||||
<label>Counter Type</label>
|
<label>Counter Type</label>
|
||||||
<options>
|
<options>
|
||||||
<option value="UNREAD">Unread</option>
|
<option value="UNREAD">Unread</option>
|
||||||
@ -132,4 +132,33 @@
|
|||||||
</parameter>
|
</parameter>
|
||||||
</config-description>
|
</config-description>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="content">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Content</label>
|
||||||
|
<description>Mail content as String (with subject filter and content transformation).</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
<config-description>
|
||||||
|
<parameter name="folder" type="text" required="true">
|
||||||
|
<label>Folder Name</label>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="subject" type="text">
|
||||||
|
<label>Subject Filter</label>
|
||||||
|
<description>A (regular expression) filter for the mail subject.</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="sender" type="text">
|
||||||
|
<label>Sender Filter</label>
|
||||||
|
<description>A (regular expression) filter for the mail sender address.</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="transformation" type="text">
|
||||||
|
<label>Transformation</label>
|
||||||
|
<description>Transformation pattern used when processing messages. Multiple transformation can be chained using "∩".</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="markAsRead" type="boolean">
|
||||||
|
<label>Mark As Read</label>
|
||||||
|
<description>Mark a processed mail as read and prevent further processing.</description>
|
||||||
|
<default>false</default>
|
||||||
|
</parameter>
|
||||||
|
</config-description>
|
||||||
|
</channel-type>
|
||||||
</thing:thing-descriptions>
|
</thing:thing-descriptions>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.mail;
|
package org.openhab.binding.mail.internal;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
@ -29,15 +29,15 @@ import org.apache.commons.mail.EmailException;
|
|||||||
import org.apache.commons.mail.HtmlEmail;
|
import org.apache.commons.mail.HtmlEmail;
|
||||||
import org.apache.commons.mail.MultiPartEmail;
|
import org.apache.commons.mail.MultiPartEmail;
|
||||||
import org.apache.commons.mail.SimpleEmail;
|
import org.apache.commons.mail.SimpleEmail;
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.mail.internal.MailBuilder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link MailBuilderTest} class defines tests for the {@link MailBuilder} class
|
* The {@link MailBuilderTest} class defines tests for the {@link MailBuilder} class
|
||||||
*
|
*
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class MailBuilderTest {
|
public class MailBuilderTest {
|
||||||
|
|
||||||
private static final String TEST_STRING = "test";
|
private static final String TEST_STRING = "test";
|
@ -22,4 +22,9 @@
|
|||||||
<suppress files=".+org.openhab.binding.yeelight.+" checks="OutsideOfLibExternalLibrariesCheck" />
|
<suppress files=".+org.openhab.binding.yeelight.+" checks="OutsideOfLibExternalLibrariesCheck" />
|
||||||
<!-- suppress header checks for imported and patched apache commons-io files in logreader binding -->
|
<!-- suppress header checks for imported and patched apache commons-io files in logreader binding -->
|
||||||
<suppress files=".+org.openhab.binding.logreader.internal.thirdparty.commonsio.+" checks="ParameterizedRegexpHeaderCheck|AuthorTagCheck" />
|
<suppress files=".+org.openhab.binding.logreader.internal.thirdparty.commonsio.+" checks="ParameterizedRegexpHeaderCheck|AuthorTagCheck" />
|
||||||
|
<!-- Mail: Do not check org.apache.commons.mail usage -->
|
||||||
|
<suppress files=".+[\\/]mail[\\/].+[\\/]MailBuilder\.java" checks="ForbiddenPackageUsageCheck"/>
|
||||||
|
<suppress files=".+[\\/]mail[\\/].+[\\/]MailBuilderTest\.java" checks="ForbiddenPackageUsageCheck"/>
|
||||||
|
<suppress files=".+[\\/]mail[\\/].+[\\/]SMTPHandler\.java" checks="ForbiddenPackageUsageCheck"/>
|
||||||
|
<suppress files=".+[\\/]mail[\\/].+[\\/]SendMailActions\.java" checks="ForbiddenPackageUsageCheck"/>
|
||||||
</suppressions>
|
</suppressions>
|
||||||
|
Loading…
Reference in New Issue
Block a user