-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(email connector): implement new email connector, Outbound SMTP, IMAP and POP3, Inbound IMAP #3132
feat(email connector): implement new email connector, Outbound SMTP, IMAP and POP3, Inbound IMAP #3132
Conversation
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
2b08f94
to
baa9aa6
Compare
connectors/email/src/main/java/io/camunda/connector/email/outbound/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/outbound/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/outbound/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/outbound/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
connectors/email/src/main/java/io/camunda/connector/email/outbound/core/JakartaExecutor.java
Fixed
Show fixed
Hide fixed
...tors/email/src/main/java/io/camunda/connector/email/outbound/core/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
...tors/email/src/main/java/io/camunda/connector/email/outbound/core/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
...tors/email/src/main/java/io/camunda/connector/email/outbound/core/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
...tors/email/src/main/java/io/camunda/connector/email/outbound/core/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaActionExecutor.java
Fixed
Show fixed
Hide fixed
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaActionExecutor.java
Fixed
Show fixed
Hide fixed
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaActionExecutor.java
Fixed
Show fixed
Hide fixed
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaActionExecutor.java
Fixed
Show fixed
Hide fixed
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaActionExecutor.java
Fixed
Show fixed
Hide fixed
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaSessionFactory.java
Fixed
Show fixed
Hide fixed
...ectors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaEmailListener.java
Fixed
Show fixed
Hide fixed
bundle/default-bundle/src/test/resources/application.properties
Outdated
Show resolved
Hide resolved
...ectors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaEmailListener.java
Outdated
Show resolved
Hide resolved
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaActionExecutor.java
Fixed
Show fixed
Hide fixed
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaActionExecutor.java
Fixed
Show fixed
Hide fixed
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaActionExecutor.java
Fixed
Show fixed
Hide fixed
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaActionExecutor.java
Fixed
Show fixed
Hide fixed
c0f1f60
to
f82fe87
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work, I left some minor comments
connectors/email/src/main/java/io/camunda/connector/email/outbound/EmailConnectorFunction.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/outbound/EmailConnectorFunction.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/outbound/EmailConnectorFunction.java
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/outbound/model/EmailRequest.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/inbound/EmailConnectorExecutable.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/outbound/protocols/Pop3.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/outbound/protocols/Imap.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/config/SmtpConfig.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/core/ActionExecutor.java
Outdated
Show resolved
Hide resolved
...ctors/email/src/main/java/io/camunda/connector/email/core/jakarta/JakartaActionExecutor.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/client/jakarta/Email.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/client/jakarta/Email.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/client/jakarta/Email.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/client/jakarta/Email.java
Outdated
Show resolved
Hide resolved
connectors/email/src/main/java/io/camunda/connector/email/client/ActionExecutor.java
Outdated
Show resolved
Hide resolved
...tors/email/src/main/java/io/camunda/connector/email/client/jakarta/JakartaEmailListener.java
Outdated
Show resolved
Hide resolved
Arrays.stream(e.getMessages()) | ||
.peek( | ||
message -> { | ||
if (markAsRead) this.jakartaUtils.markAsSeen(message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldnt it be marked after the correlation? If the correlation fails we have already seen
the message and wont process it again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We create a new process when a new message is received (idle https://en.wikipedia.org/wiki/IMAP_IDLE ), not on every unseen email, so even if it was marked as seen
and the correlation fails, It would not be processed again..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But dont we want to reprocess it?
connectorContext.correlateWithResult( | ||
new ReadEmailResponse( | ||
email.getMessageId(), | ||
email.getFrom(), | ||
email.getSubject(), | ||
email.getSize(), | ||
email.getBody().getBodyAsPlainText(), | ||
email.getBody().getBodyAsHtml()))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be extracted into a separate method and switched to a map(this::correlateEmail)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
} | ||
} | ||
|
||
private List<String> createInboxList(Object folderToListen) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use a proper type like List<Inbox>
? or something similar without string handling?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is really just to format the object, we dont know if that is a String comma separated or already a List made by the Feel engine
} | ||
this.store.close(); | ||
} catch (MessagingException e) { | ||
throw new RuntimeException(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logging this error
would help to debug it.
import jakarta.validation.Valid; | ||
import jakarta.validation.constraints.NotNull; | ||
|
||
public class EmailProperties { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EmailProperties
is quite generic. What about EmailInboundConnectorProperties
.
import jakarta.validation.Valid; | ||
import jakarta.validation.constraints.NotNull; | ||
|
||
public class EmailListenerData { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be a record.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name is quite generic. What about EmailListenerConfig
optional = true, | ||
feel = Property.FeelMode.optional, | ||
binding = @TemplateProperty.PropertyBinding(name = "data.folderToListen")) | ||
private Object folderToListen; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets go with a proper type instead of Object
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I did not know that it is that complex. Would it be possible to map this with a proper model? Like ImapSearchQuery
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Object can really depends:
I can have
{
"field":"FROM",
"value":"[email protected]"
}
or the example given previously, so the root object is not always the same
Great work @mathias-vandaele. Added some comments. |
return new JakartaEmailActionExecutor(sessionFactory, objectMapper); | ||
} | ||
|
||
public Object execute(EmailRequest emailRequest) { |
Check notice
Code scanning / CodeQL
Missing Override annotation Note
EmailActionExecutor.execute
return new JakartaEmailListener(sessionFactory); | ||
} | ||
|
||
public void startListener(InboundConnectorContext context) { |
Check notice
Code scanning / CodeQL
Missing Override annotation Note
EmailListener.startListener
connectors/email/src/main/java/io/camunda/connector/email/client/jakarta/JakartaUtils.java
Fixed
Show fixed
Hide fixed
...tors/email/src/main/java/io/camunda/connector/email/client/jakarta/JakartaEmailListener.java
Fixed
Show fixed
Hide fixed
...tors/email/src/main/java/io/camunda/connector/email/client/jakarta/JakartaEmailListener.java
Fixed
Show fixed
Hide fixed
...tors/email/src/main/java/io/camunda/connector/email/client/jakarta/JakartaEmailListener.java
Fixed
Show fixed
Hide fixed
switch (correlationResult) { | ||
case CorrelationResult.Failure failure -> { | ||
switch (failure.handlingStrategy()) { | ||
case CorrelationFailureHandlingStrategy.ForwardErrorToUpstream __ -> {} |
Check notice
Code scanning / CodeQL
Unread local variable Note
case CorrelationResult.Failure failure -> { | ||
switch (failure.handlingStrategy()) { | ||
case CorrelationFailureHandlingStrategy.ForwardErrorToUpstream __ -> {} | ||
case CorrelationFailureHandlingStrategy.Ignore __ -> |
Check notice
Code scanning / CodeQL
Unread local variable Note
executePostProcess(message, emailListenerConfig); | ||
} | ||
} | ||
case CorrelationResult.Success __ -> executePostProcess(message, emailListenerConfig); |
Check notice
Code scanning / CodeQL
Unread local variable Note
// Given | ||
SmtpConfig smtpConfig = new SmtpConfig("smtp.example.com", 587, CryptographicProtocol.TLS); | ||
Smtp smtp = new Smtp(null, smtpConfig); | ||
Authentication auth = mock(SimpleAuthentication.class); |
Check notice
Code scanning / CodeQL
Unread local variable Note test
// Given | ||
SmtpConfig smtpConfig = new SmtpConfig("smtp.example.com", 25, CryptographicProtocol.NONE); | ||
Smtp smtp = new Smtp(null, smtpConfig); | ||
Authentication auth = mock(SimpleAuthentication.class); |
Check notice
Code scanning / CodeQL
Unread local variable Note test
void testCreatePropertiesWithPop3AndNoSecurity() { | ||
// Given | ||
Pop3Config pop3Config = new Pop3Config("pop3.example.com", 110, CryptographicProtocol.NONE); | ||
Authentication auth = mock(SimpleAuthentication.class); |
Check notice
Code scanning / CodeQL
Unread local variable Note test
// Given | ||
Pop3Config pop3Config = new Pop3Config("pop3.example.com", 995, CryptographicProtocol.TLS); | ||
|
||
Authentication auth = mock(SimpleAuthentication.class); |
Check notice
Code scanning / CodeQL
Unread local variable Note test
// Given | ||
ImapConfig imapConfig = new ImapConfig("imap.example.com", 143, CryptographicProtocol.NONE); | ||
|
||
Authentication auth = mock(SimpleAuthentication.class); |
Check notice
Code scanning / CodeQL
Unread local variable Note test
// Given | ||
ImapConfig imapConfig = new ImapConfig("imap.tls-example.com", 993, CryptographicProtocol.TLS); | ||
// When | ||
Authentication auth = mock(SimpleAuthentication.class); |
Check notice
Code scanning / CodeQL
Unread local variable Note test
ImapConfig imapConfig = new ImapConfig("imap.ssl-example.com", 993, CryptographicProtocol.SSL); | ||
|
||
// When | ||
Authentication auth = mock(SimpleAuthentication.class); |
Check notice
Code scanning / CodeQL
Unread local variable Note test
@johnBgood Would you be ok for final approvement ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing blocking, just a few comments 👍
name = "type", | ||
defaultValue = "simple", | ||
description = "Specify the Email authentication strategy.") | ||
public sealed interface Authentication permits SimpleAuthentication {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we still need this interface if there's only a SimpleAuth ? It can be good for the future if we plan to support other types, so I'm just flagging it in case
import io.camunda.connector.api.inbound.InboundConnectorContext; | ||
|
||
public interface EmailListener { | ||
void startListener(InboundConnectorContext context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe start/stop would be sufficient
Action action = protocol.getProtocolAction(); | ||
Session session = jakartaUtils.createSession(protocol.getConfiguration()); | ||
return switch (action) { | ||
case SmtpSendEmail smtpSendEmail -> smtpSendEmail(smtpSendEmail, authentication, session); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd split the methods called here into 3 different classes (imap, smtp, pop3) to avoid adding cognitive load to this class.
This would also enable testability for each of these methods.
import jakarta.mail.search.*; | ||
import java.util.*; | ||
|
||
public class JakartaEmailActionExecutor implements EmailActionExecutor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class is very important, it should have a Logger and proper logging in place, so that we can debug it some day
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class JakartaUtils { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This Utils class is huge, not sure if we can/want to refactor it a bit but I feel it touches upon too many things
Description
New implementation of the email connectors.
It has not been completely polished but ready for review.
I would like to come back on the label for the ET, and add new tests
Related issues
related #3108
related #3213
related #3214
related #3215