You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/03/20 12:15:43 UTC

[james-project] branch master updated (24866d6 -> f49b5b0)

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git.


    from 24866d6  JAMES-3082 define different wait times for event bus in tests
     new 058a83f  Upgrade play-json to 2.8
     new 58b1d87  JAMES-3119 Strong type ProtocolSession
     new b2faf77  JAMES-3113 LocalResources: cosmetic fixes
     new b7268ee  JAMES-3113 LocalResources: rely on Username POJO
     new 262d064  JAMES-3113 LocalResources: propagate exceptions
     new 23c934b  JAMES-3113 JamesMailetContext: Remove unused storeMail method
     new 37011e6  JAMES-3113 UsersRepository::getUsername
     new f49b5b0  JAMES-3105 Limit concurrency of mailbox counters recomputation

The 8 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../mail/task/RecomputeMailboxCountersService.java |   7 +-
 mailbox/event/json/pom.xml                         |   4 +-
 .../apache/james/event/json/EventSerializer.scala  |   6 +-
 .../james/event/json/dtos/QuotaCountTest.java      |   6 +-
 .../james/event/json/dtos/QuotaSizeTest.java       |   7 +-
 .../james/transport/mailets/AbstractSign.java      |   2 +-
 .../james/protocols/api/ProtocolSession.java       |  83 +++++++++++++--
 .../james/protocols/api/ProtocolSessionImpl.java   |  45 ++++----
 .../james/protocols/api/ProtocolSessionTest.java   |   8 +-
 .../lmtp/core/DataLineMessageHookHandler.java      |   4 +-
 .../apache/james/protocols/pop3/POP3Session.java   |  11 +-
 .../pop3/core/AbstractApopCmdHandler.java          |   7 +-
 .../james/protocols/pop3/core/DeleCmdHandler.java  |   8 +-
 .../james/protocols/pop3/core/ListCmdHandler.java  |  11 +-
 .../protocols/pop3/core/MessageMetaDataUtils.java  |  12 +--
 .../james/protocols/pop3/core/QuitCmdHandler.java  |   4 +-
 .../james/protocols/pop3/core/RetrCmdHandler.java  |   5 +-
 .../james/protocols/pop3/core/RsetCmdHandler.java  |   2 +-
 .../james/protocols/pop3/core/StatCmdHandler.java  |  10 +-
 .../james/protocols/pop3/core/TopCmdHandler.java   |   4 +-
 .../james/protocols/pop3/core/UidlCmdHandler.java  |   8 +-
 .../apache/james/protocols/smtp/SMTPSession.java   |  13 ++-
 .../james/protocols/smtp/SMTPSessionImpl.java      |  22 ++--
 .../smtp/core/AbstractAddHeadersFilter.java        |   9 +-
 ...ractSenderAuthIdentifyVerificationRcptHook.java |   2 +-
 .../james/protocols/smtp/core/DataCmdHandler.java  |  14 +--
 .../smtp/core/DataLineMessageHookHandler.java      |  20 +++-
 .../james/protocols/smtp/core/MailCmdHandler.java  |  20 ++--
 .../james/protocols/smtp/core/RcptCmdHandler.java  |  31 +++---
 .../smtp/core/ReceivedDataLineFilter.java          |  18 ++--
 .../smtp/core/SeparatingDataLineFilter.java        |   5 +-
 .../protocols/smtp/core/UnknownCmdHandler.java     |   7 +-
 .../smtp/core/esmtp/MailSizeEsmtpExtension.java    |  29 +++---
 .../smtp/core/fastfail/DNSRBLHandler.java          |  21 ++--
 .../smtp/core/fastfail/MaxUnknownCmdHandler.java   |  13 ++-
 .../core/fastfail/ResolvableEhloHeloHandler.java   |  12 +--
 .../core/fastfail/SupressDuplicateRcptHandler.java |  38 +++----
 .../smtp/core/fastfail/DNSRBLHandlerTest.java      |  73 +++++++------
 .../smtp/core/fastfail/MaxRcptHandlerTest.java     |   4 +-
 .../core/fastfail/MaxUnknownCmdHandlerTest.java    |  32 ++++--
 .../fastfail/ResolvableEhloHeloHandlerTest.java    |  60 ++++++-----
 .../fastfail/ValidSenderDomainHandlerTest.java     |  35 ++++---
 .../protocols/smtp/utils/BaseFakeSMTPSession.java  |  14 ++-
 .../org/apache/james/user/api/UsersRepository.java |   2 +-
 .../user/ldap/ReadOnlyUsersLDAPRepositoryTest.java |   4 +-
 .../user/lib/AbstractUsersRepositoryTest.java      |   6 +-
 .../mailetcontainer/impl/JamesMailetContext.java   |  19 ----
 .../mailetcontainer/{ => impl}/LocalResources.java |  49 ++++-----
 .../META-INF/spring/mailetcontainer-context.xml    |   2 +-
 .../impl/JamesMailetContextTest.java               | 115 ++++++++++++++++++---
 .../james/transport/mailets/SpamAssassin.java      |   2 +-
 .../james/transport/mailets/ToSenderFolder.java    |   2 +-
 .../transport/mailets/WithStorageDirective.java    |   2 +-
 .../mailets/delivery/SimpleMailStore.java          |   2 +-
 .../transport/mailets/jsieve/ResourceLocator.java  |   2 +-
 .../mailets/jsieve/delivery/SievePoster.java       |   2 +-
 .../james/transport/matchers/IsOverQuota.java      |   2 +-
 .../transport/mailets/ResourceLocatorTest.java     |   4 +-
 .../mailets/delivery/LocalDeliveryTest.java        |   6 +-
 .../mailets/delivery/SieveIntegrationTest.java     |  10 +-
 .../mailets/delivery/SimpleMailStoreTest.java      |   6 +-
 .../mailets/delivery/ToRecipientFolderTest.java    |   8 +-
 .../james/transport/matchers/IsOverQuotaTest.java  |   8 +-
 .../apache/james/fetchmail/MessageProcessor.java   |   2 +-
 .../mailet/ExtractMDNOriginalJMAPMessageId.java    |   2 +-
 .../james/jmap/mailet/filter/JMAPFiltering.java    |   2 +-
 .../hook/MailboxDeliverToRecipientHandler.java     |   2 +-
 .../DataLineJamesMessageHookHandler.java           |  11 +-
 .../org/apache/james/smtpserver/SMTPConstants.java |   8 +-
 .../SenderAuthIdentifyVerificationRcptHook.java    |   2 +-
 .../james/smtpserver/fastfail/SPFHandler.java      |  29 +++---
 .../james/smtpserver/fastfail/URIRBLHandler.java   |  18 ++--
 .../smtpserver/fastfail/ValidRcptHandler.java      |   2 +-
 .../netty/SMTPChannelUpstreamHandler.java          |   4 +-
 .../apache/james/smtpserver/SPFHandlerTest.java    |  41 +++++---
 .../james/smtpserver/SpamAssassinHandlerTest.java  |  41 +++++---
 .../apache/james/smtpserver/URIRBLHandlerTest.java |  41 +++++---
 .../james/smtpserver/ValidRcptHandlerTest.java     |  39 ++++---
 .../apache/james/smtpserver/ValidRcptMXTest.java   |  38 ++++---
 .../apache/james/webadmin/routes/AliasRoutes.java  |   2 +-
 .../james/webadmin/routes/ForwardRoutes.java       |   2 +-
 .../apache/james/webadmin/routes/GroupsRoutes.java |   2 +-
 upgrade-instructions.md                            |  18 ++++
 83 files changed, 792 insertions(+), 513 deletions(-)
 copy server/blob/blob-api/src/test/java/org/apache/james/blob/api/BlobTypeTest.java => protocols/api/src/test/java/org/apache/james/protocols/api/ProtocolSessionTest.java (86%)
 rename server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/{ => impl}/LocalResources.java (68%)


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 04/08: JAMES-3113 LocalResources: rely on Username POJO

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit b7268eee7880b6bcd9a45c925f28a3db618064d4
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Mar 18 10:13:31 2020 +0700

    JAMES-3113 LocalResources: rely on Username POJO
---
 .../apache/james/mailetcontainer/impl/LocalResources.java | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
index 7cdeab5..509f80b 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
@@ -68,16 +68,11 @@ class LocalResources {
             return false;
         }
         try {
-            if (!name.contains("@")) {
-                try {
-                    return isLocalEmail(new MailAddress(name.toLowerCase(Locale.US), domains.getDefaultDomain().asString()));
-                } catch (DomainListException e) {
-                    LOGGER.error("Unable to access DomainList", e);
-                    return false;
-                }
-            } else {
-                return isLocalEmail(new MailAddress(name.toLowerCase(Locale.US)));
-            }
+            MailAddress mailAddress = Username.of(name).withDefaultDomain(domains.getDefaultDomain()).asMailAddress();
+            return isLocalEmail(mailAddress);
+        } catch (DomainListException e) {
+            LOGGER.error("Unable to access DomainList", e);
+            return false;
         } catch (ParseException e) {
             LOGGER.info("Error checking isLocalUser for user {}", name, e);
             return false;


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 06/08: JAMES-3113 JamesMailetContext: Remove unused storeMail method

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 23c934bdc93d08df348950cecb29c0d78c4a7ed6
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Mar 18 10:39:01 2020 +0700

    JAMES-3113 JamesMailetContext: Remove unused storeMail method
    
    This public method is unused, not implemented, and not part of the interface.
---
 .../james/mailetcontainer/impl/JamesMailetContext.java | 18 ------------------
 .../james/mailetcontainer/impl/LocalResources.java     |  5 +----
 2 files changed, 1 insertion(+), 22 deletions(-)

diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java
index f4bb580..98eb92f 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java
@@ -405,24 +405,6 @@ public class JamesMailetContext implements MailetContext, Configurable, Disposab
         }
     }
 
-    /**
-     * <p>
-     * This method has been moved to LocalDelivery (the only client of the
-     * method). Now we can safely remove it from the Mailet API and from this
-     * implementation of MailetContext.
-     * </p>
-     * <p>
-     * The local field localDeliveryMailet will be removed when we remove the
-     * storeMail method.
-     * </p>
-     *
-     * @deprecated since 2.2.0 look at the LocalDelivery code to find out how to
-     *             do the local delivery.
-     */
-    public void storeMail(MailAddress sender, MailAddress recipient, MimeMessage msg) {
-        throw new UnsupportedOperationException("Was removed");
-    }
-
     @Override
     public void configure(HierarchicalConfiguration<ImmutableNode> config) throws ConfigurationException {
         this.rootMailQueue = mailQueueFactory.createQueue(MailQueueFactory.SPOOL);
diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
index 5ee133f..9332ee3 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
@@ -20,13 +20,13 @@
 package org.apache.james.mailetcontainer.impl;
 
 import java.util.EnumSet;
-import java.util.Locale;
 
 import javax.inject.Inject;
 import javax.mail.internet.ParseException;
 
 import org.apache.james.core.Domain;
 import org.apache.james.core.MailAddress;
+import org.apache.james.core.Username;
 import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.domainlist.api.DomainListException;
 import org.apache.james.rrt.api.RecipientRewriteTable;
@@ -34,13 +34,10 @@ import org.apache.james.rrt.api.RecipientRewriteTableException;
 import org.apache.james.rrt.lib.Mapping;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.github.fge.lambdas.Throwing;
 
 class LocalResources {
-    private static final Logger LOGGER = LoggerFactory.getLogger(LocalResources.class);
     private static final EnumSet<Mapping.Type> ALIAS_TYPES = EnumSet.of(Mapping.Type.Alias, Mapping.Type.DomainAlias);
 
     private final UsersRepository localUsers;


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 05/08: JAMES-3113 LocalResources: propagate exceptions

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 262d064003c1baf4a7343c4ac0928c952e990214
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Mar 18 10:37:19 2020 +0700

    JAMES-3113 LocalResources: propagate exceptions
    
    Avoid taking wrong business decisions upon technical exceptions
---
 .../james/mailetcontainer/impl/LocalResources.java |  15 ++-
 .../impl/JamesMailetContextTest.java               | 114 +++++++++++++++++++--
 2 files changed, 110 insertions(+), 19 deletions(-)

diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
index 509f80b..5ee133f 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
@@ -58,8 +58,7 @@ class LocalResources {
         try {
             return domains.containsDomain(domain);
         } catch (DomainListException e) {
-            LOGGER.error("Unable to retrieve domains", e);
-            return false;
+            throw new RuntimeException("Unable to retrieve domains", e);
         }
     }
 
@@ -71,11 +70,9 @@ class LocalResources {
             MailAddress mailAddress = Username.of(name).withDefaultDomain(domains.getDefaultDomain()).asMailAddress();
             return isLocalEmail(mailAddress);
         } catch (DomainListException e) {
-            LOGGER.error("Unable to access DomainList", e);
-            return false;
+            throw new RuntimeException("Unable to retrieve domains", e);
         } catch (ParseException e) {
-            LOGGER.info("Error checking isLocalUser for user {}", name, e);
-            return false;
+            throw new RuntimeException("Unable to parse mail address", e);
         }
     }
 
@@ -87,8 +84,10 @@ class LocalResources {
             try {
                 return isLocaluser(mailAddress)
                     || isLocalAlias(mailAddress);
-            } catch (UsersRepositoryException | RecipientRewriteTable.ErrorMappingException | RecipientRewriteTableException e) {
-                LOGGER.error("Unable to access UsersRepository", e);
+            } catch (UsersRepositoryException e) {
+                throw new RuntimeException("Unable to retrieve users", e);
+            } catch (RecipientRewriteTable.ErrorMappingException | RecipientRewriteTableException e) {
+                throw new RuntimeException("Unable to retrieve RRTs", e);
             }
         }
         return false;
diff --git a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java
index 9cbf559..ea2320b 100644
--- a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java
+++ b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java
@@ -20,7 +20,11 @@
 package org.apache.james.mailetcontainer.impl;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
@@ -36,12 +40,15 @@ import org.apache.james.core.MailAddress;
 import org.apache.james.core.Username;
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.api.DomainListException;
 import org.apache.james.domainlist.lib.DomainListConfiguration;
 import org.apache.james.domainlist.memory.MemoryDomainList;
 import org.apache.james.queue.api.MailQueue;
 import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.james.rrt.api.RecipientRewriteTableException;
 import org.apache.james.rrt.memory.MemoryRecipientRewriteTable;
 import org.apache.james.server.core.MailImpl;
+import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.user.memory.MemoryUsersRepository;
 import org.apache.james.util.MimeMessageUtil;
 import org.apache.mailet.Mail;
@@ -56,11 +63,11 @@ import org.mockito.ArgumentCaptor;
 import com.google.common.collect.ImmutableList;
 
 public class JamesMailetContextTest {
-    public static final Domain DOMAIN_COM = Domain.of("domain.com");
-    public static final String USERNAME = "user";
-    public static final Username USERMAIL = Username.of(USERNAME + "@" + DOMAIN_COM.name());
-    public static final String PASSWORD = "password";
-    public static final DNSService DNS_SERVICE = null;
+    private static final Domain DOMAIN_COM = Domain.of("domain.com");
+    private static final String USERNAME = "user";
+    private static final Username USERMAIL = Username.of(USERNAME + "@" + DOMAIN_COM.name());
+    private static final String PASSWORD = "password";
+    private static final DNSService DNS_SERVICE = null;
 
     @Rule
     public final JUnitSoftAssertions softly = new JUnitSoftAssertions();
@@ -70,18 +77,19 @@ public class JamesMailetContextTest {
     private JamesMailetContext testee;
     private MailAddress mailAddress;
     private MailQueue spoolMailQueue;
+    private MemoryRecipientRewriteTable recipientRewriteTable;
 
     @Before
     @SuppressWarnings("unchecked")
     public void setUp() throws Exception {
-        domainList = new MemoryDomainList(DNS_SERVICE);
+        domainList = spy(new MemoryDomainList(DNS_SERVICE));
         domainList.configure(DomainListConfiguration.builder()
             .autoDetect(false)
             .autoDetectIp(false)
             .build());
 
-        usersRepository = MemoryUsersRepository.withVirtualHosting(domainList);
-        MemoryRecipientRewriteTable recipientRewriteTable = new MemoryRecipientRewriteTable();
+        usersRepository = spy(MemoryUsersRepository.withVirtualHosting(domainList));
+        recipientRewriteTable = spy(new MemoryRecipientRewriteTable());
         recipientRewriteTable.configure(new BaseHierarchicalConfiguration());
         MailQueueFactory<MailQueue> mailQueueFactory = mock(MailQueueFactory.class);
         spoolMailQueue = mock(MailQueue.class);
@@ -104,6 +112,52 @@ public class JamesMailetContextTest {
     }
 
     @Test
+    public void isLocalServerShouldPropagateDomainExceptions() throws Exception {
+        when(domainList.getDomains()).thenThrow(new DomainListException("fail!"));
+
+        assertThatThrownBy(() -> testee.isLocalServer(DOMAIN_COM))
+            .isInstanceOf(RuntimeException.class);
+    }
+
+    @Test
+    public void isLocalUserShouldPropagateDomainExceptions() throws Exception {
+        when(domainList.getDefaultDomain()).thenThrow(new DomainListException("fail!"));
+
+        assertThatThrownBy(() -> testee.isLocalUser("user"))
+            .isInstanceOf(RuntimeException.class);
+    }
+
+    @Test
+    public void isLocalUserShouldPropagateUserExceptions() throws Exception {
+        domainList.configure(DomainListConfiguration.builder()
+            .autoDetect(false)
+            .autoDetectIp(false)
+            .defaultDomain(Domain.of("any"))
+            .build());
+        domainList.addDomain(DOMAIN_COM);
+
+        doThrow(new UsersRepositoryException("fail!")).when(usersRepository).contains(any());
+
+        assertThatThrownBy(() -> testee.isLocalUser(USERNAME))
+            .isInstanceOf(RuntimeException.class);
+    }
+
+    @Test
+    public void isLocalUserShouldPropagateRrtExceptions() throws Exception {
+        domainList.configure(DomainListConfiguration.builder()
+            .autoDetect(false)
+            .autoDetectIp(false)
+            .defaultDomain(Domain.of("any"))
+            .build());
+        domainList.addDomain(DOMAIN_COM);
+
+        doThrow(new RecipientRewriteTableException("fail!")).when(recipientRewriteTable).getResolvedMappings(any(), any(), any());
+
+        assertThatThrownBy(() -> testee.isLocalUser(USERNAME))
+            .isInstanceOf(RuntimeException.class);
+    }
+
+    @Test
     public void isLocalServerShouldBeTrueWhenDomainExist() throws Exception {
         domainList.addDomain(DOMAIN_COM);
 
@@ -146,12 +200,12 @@ public class JamesMailetContextTest {
     }
 
     @Test
-    public void isLocalUserShouldBeFalseWhenUsernameDoNotExist() throws Exception {
+    public void isLocalUserShouldBeFalseWhenUsernameDoNotExist() {
         assertThat(testee.isLocalUser(USERMAIL.asString())).isFalse();
     }
 
     @Test
-    public void isLocalEmailShouldBeFalseWhenUsernameDoNotExist() throws Exception {
+    public void isLocalEmailShouldBeFalseWhenUsernameDoNotExist() {
         assertThat(testee.isLocalEmail(mailAddress)).isFalse();
     }
 
@@ -171,11 +225,49 @@ public class JamesMailetContextTest {
     }
 
     @Test
-    public void isLocalEmailShouldBeFalseWhenMailIsNull() throws Exception {
+    public void isLocalEmailShouldBeFalseWhenMailIsNull() {
         assertThat(testee.isLocalEmail(null)).isFalse();
     }
 
     @Test
+    public void isLocalEmailShouldPropagateDomainExceptions() throws Exception {
+        when(domainList.getDomains()).thenThrow(new DomainListException("fail!"));
+
+        assertThatThrownBy(() -> testee.isLocalEmail(mailAddress))
+            .isInstanceOf(RuntimeException.class);
+    }
+
+    @Test
+    public void isLocalEmailShouldPropagateUserExceptions() throws Exception {
+        domainList.configure(DomainListConfiguration.builder()
+            .autoDetect(false)
+            .autoDetectIp(false)
+            .defaultDomain(Domain.of("any"))
+            .build());
+        domainList.addDomain(DOMAIN_COM);
+
+        doThrow(new UsersRepositoryException("fail!")).when(usersRepository).contains(any());
+
+        assertThatThrownBy(() -> testee.isLocalEmail(mailAddress))
+            .isInstanceOf(RuntimeException.class);
+    }
+
+    @Test
+    public void isLocalEmailShouldPropagateRrtExceptions() throws Exception {
+        domainList.configure(DomainListConfiguration.builder()
+            .autoDetect(false)
+            .autoDetectIp(false)
+            .defaultDomain(Domain.of("any"))
+            .build());
+        domainList.addDomain(DOMAIN_COM);
+
+        doThrow(new RecipientRewriteTableException("fail!")).when(recipientRewriteTable).getResolvedMappings(any(), any(), any());
+
+        assertThatThrownBy(() -> testee.isLocalEmail(mailAddress))
+            .isInstanceOf(RuntimeException.class);
+    }
+
+    @Test
     public void bounceShouldNotFailWhenNonConfiguredPostmaster() throws Exception {
         MailImpl mail = MailImpl.builder()
             .name("mail1")


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 03/08: JAMES-3113 LocalResources: cosmetic fixes

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit b2faf772d01c38550f1f55d070fc4315cc45eeff
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Mar 18 10:11:53 2020 +0700

    JAMES-3113 LocalResources: cosmetic fixes
    
     - Visibility
     - Location
---
 .../james/mailetcontainer/impl/JamesMailetContext.java |  1 -
 .../mailetcontainer/{ => impl}/LocalResources.java     | 18 +++++++++---------
 .../META-INF/spring/mailetcontainer-context.xml        |  2 +-
 .../mailetcontainer/impl/JamesMailetContextTest.java   |  1 -
 4 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java
index 5d513a4..f4bb580 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java
@@ -53,7 +53,6 @@ import org.apache.james.domainlist.api.DomainListException;
 import org.apache.james.lifecycle.api.Configurable;
 import org.apache.james.lifecycle.api.Disposable;
 import org.apache.james.lifecycle.api.LifecycleUtil;
-import org.apache.james.mailetcontainer.LocalResources;
 import org.apache.james.queue.api.MailQueue;
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.server.core.MailImpl;
diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/LocalResources.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
similarity index 89%
rename from server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/LocalResources.java
rename to server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
index ce83023..7cdeab5 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/LocalResources.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
@@ -17,7 +17,7 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.mailetcontainer;
+package org.apache.james.mailetcontainer.impl;
 
 import java.util.EnumSet;
 import java.util.Locale;
@@ -39,22 +39,22 @@ import org.slf4j.LoggerFactory;
 
 import com.github.fge.lambdas.Throwing;
 
-public class LocalResources {
+class LocalResources {
     private static final Logger LOGGER = LoggerFactory.getLogger(LocalResources.class);
     private static final EnumSet<Mapping.Type> ALIAS_TYPES = EnumSet.of(Mapping.Type.Alias, Mapping.Type.DomainAlias);
 
-    private final UsersRepository localusers;
+    private final UsersRepository localUsers;
     private final DomainList domains;
     private final RecipientRewriteTable recipientRewriteTable;
 
     @Inject
-    public LocalResources(UsersRepository localusers, DomainList domains, RecipientRewriteTable recipientRewriteTable) {
-        this.localusers = localusers;
+    LocalResources(UsersRepository localUsers, DomainList domains, RecipientRewriteTable recipientRewriteTable) {
+        this.localUsers = localUsers;
         this.domains = domains;
         this.recipientRewriteTable = recipientRewriteTable;
     }
 
-    public boolean isLocalServer(Domain domain) {
+    boolean isLocalServer(Domain domain) {
         try {
             return domains.containsDomain(domain);
         } catch (DomainListException e) {
@@ -63,7 +63,7 @@ public class LocalResources {
         }
     }
 
-    public boolean isLocalUser(String name) {
+    boolean isLocalUser(String name) {
         if (name == null) {
             return false;
         }
@@ -84,7 +84,7 @@ public class LocalResources {
         }
     }
 
-    public boolean isLocalEmail(MailAddress mailAddress) {
+    boolean isLocalEmail(MailAddress mailAddress) {
         if (mailAddress != null) {
             if (!isLocalServer(mailAddress.getDomain())) {
                 return false;
@@ -100,7 +100,7 @@ public class LocalResources {
     }
 
     private boolean isLocaluser(MailAddress mailAddress) throws UsersRepositoryException {
-        return localusers.contains(localusers.getUser(mailAddress));
+        return localUsers.contains(localUsers.getUser(mailAddress));
     }
 
     private boolean isLocalAlias(MailAddress mailAddress) throws UsersRepositoryException, RecipientRewriteTable.ErrorMappingException, RecipientRewriteTableException {
diff --git a/server/mailet/mailetcontainer-camel/src/main/resources/META-INF/spring/mailetcontainer-context.xml b/server/mailet/mailetcontainer-camel/src/main/resources/META-INF/spring/mailetcontainer-context.xml
index 783aab9..cbab870 100644
--- a/server/mailet/mailetcontainer-camel/src/main/resources/META-INF/spring/mailetcontainer-context.xml
+++ b/server/mailet/mailetcontainer-camel/src/main/resources/META-INF/spring/mailetcontainer-context.xml
@@ -33,7 +33,7 @@
       it is used - Seems like a Spring bug.
     -->
     <bean id="mailetcontext" class="org.apache.james.mailetcontainer.impl.JamesMailetContext" autowire="byType"/>
-    <bean id="localResources" class="org.apache.james.mailetcontainer.LocalResources" autowire="byType"/>
+    <bean id="localResources" class="org.apache.james.mailetcontainer.impl.LocalResources" autowire="byType"/>
     <bean id="mailspooler" class="org.apache.james.mailetcontainer.impl.JamesMailSpooler" autowire="byType"/>
     
 </beans>
diff --git a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java
index 87ac492..9cbf559 100644
--- a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java
+++ b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java
@@ -38,7 +38,6 @@ import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.dnsservice.api.DNSService;
 import org.apache.james.domainlist.lib.DomainListConfiguration;
 import org.apache.james.domainlist.memory.MemoryDomainList;
-import org.apache.james.mailetcontainer.LocalResources;
 import org.apache.james.queue.api.MailQueue;
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.rrt.memory.MemoryRecipientRewriteTable;


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 07/08: JAMES-3113 UsersRepository::getUsername

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 37011e6e3cfe9301cabb3841bc26de83608ed1de
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Mar 20 10:04:41 2020 +0700

    JAMES-3113 UsersRepository::getUsername
---
 .../java/org/apache/james/transport/mailets/AbstractSign.java  |  2 +-
 .../main/java/org/apache/james/user/api/UsersRepository.java   |  2 +-
 .../james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java       |  4 ++--
 .../org/apache/james/user/lib/AbstractUsersRepositoryTest.java |  6 +++---
 .../org/apache/james/mailetcontainer/impl/LocalResources.java  |  2 +-
 .../java/org/apache/james/transport/mailets/SpamAssassin.java  |  2 +-
 .../org/apache/james/transport/mailets/ToSenderFolder.java     |  2 +-
 .../apache/james/transport/mailets/WithStorageDirective.java   |  2 +-
 .../james/transport/mailets/delivery/SimpleMailStore.java      |  2 +-
 .../apache/james/transport/mailets/jsieve/ResourceLocator.java |  2 +-
 .../james/transport/mailets/jsieve/delivery/SievePoster.java   |  2 +-
 .../java/org/apache/james/transport/matchers/IsOverQuota.java  |  2 +-
 .../apache/james/transport/mailets/ResourceLocatorTest.java    |  4 ++--
 .../james/transport/mailets/delivery/LocalDeliveryTest.java    |  6 +++---
 .../james/transport/mailets/delivery/SieveIntegrationTest.java | 10 +++++-----
 .../james/transport/mailets/delivery/SimpleMailStoreTest.java  |  6 +++---
 .../transport/mailets/delivery/ToRecipientFolderTest.java      |  8 ++++----
 .../org/apache/james/transport/matchers/IsOverQuotaTest.java   |  8 ++++----
 .../main/java/org/apache/james/fetchmail/MessageProcessor.java |  2 +-
 .../james/jmap/mailet/ExtractMDNOriginalJMAPMessageId.java     |  2 +-
 .../org/apache/james/jmap/mailet/filter/JMAPFiltering.java     |  2 +-
 .../lmtpserver/hook/MailboxDeliverToRecipientHandler.java      |  2 +-
 .../smtpserver/SenderAuthIdentifyVerificationRcptHook.java     |  2 +-
 .../org/apache/james/smtpserver/fastfail/ValidRcptHandler.java |  2 +-
 .../java/org/apache/james/webadmin/routes/AliasRoutes.java     |  2 +-
 .../java/org/apache/james/webadmin/routes/ForwardRoutes.java   |  2 +-
 .../java/org/apache/james/webadmin/routes/GroupsRoutes.java    |  2 +-
 27 files changed, 45 insertions(+), 45 deletions(-)

diff --git a/mailet/crypto/src/main/java/org/apache/james/transport/mailets/AbstractSign.java b/mailet/crypto/src/main/java/org/apache/james/transport/mailets/AbstractSign.java
index 3a3b6f3..e19cc89 100644
--- a/mailet/crypto/src/main/java/org/apache/james/transport/mailets/AbstractSign.java
+++ b/mailet/crypto/src/main/java/org/apache/james/transport/mailets/AbstractSign.java
@@ -610,7 +610,7 @@ public abstract class AbstractSign extends GenericMailet {
 
     private Username getUsername(MailAddress mailAddress) {
         try {
-            return usersRepository.getUser(mailAddress);
+            return usersRepository.getUsername(mailAddress);
         } catch (UsersRepositoryException e) {
             throw new RuntimeException(e);
         }
diff --git a/server/data/data-api/src/main/java/org/apache/james/user/api/UsersRepository.java b/server/data/data-api/src/main/java/org/apache/james/user/api/UsersRepository.java
index dae2654..0f8809e 100644
--- a/server/data/data-api/src/main/java/org/apache/james/user/api/UsersRepository.java
+++ b/server/data/data-api/src/main/java/org/apache/james/user/api/UsersRepository.java
@@ -134,7 +134,7 @@ public interface UsersRepository {
      *
      * @return Username used by James for this mailAddress
      */
-    default Username getUser(MailAddress mailAddress) throws UsersRepositoryException {
+    default Username getUsername(MailAddress mailAddress) throws UsersRepositoryException {
         if (supportVirtualHosting()) {
             return Username.of(mailAddress.asString());
         } else {
diff --git a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
index 6b22f32..8d0fd20 100644
--- a/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
+++ b/server/data/data-ldap/src/test/java/org/apache/james/user/ldap/ReadOnlyUsersLDAPRepositoryTest.java
@@ -202,13 +202,13 @@ class ReadOnlyUsersLDAPRepositoryTest {
         @Test
         void containsWithGetUserShouldBeTrue() throws Exception {
             ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfiguration(ldapContainer));
-            assertThat(ldapRepository.contains(ldapRepository.getUser(JAMES_USER_MAIL.asMailAddress()))).isTrue();
+            assertThat(ldapRepository.contains(ldapRepository.getUsername(JAMES_USER_MAIL.asMailAddress()))).isTrue();
         }
 
         @Test
         void containsWithGetUserShouldBeTrueWithVirtualHosting() throws Exception {
             ReadOnlyUsersLDAPRepository ldapRepository = startUsersRepository(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer));
-            assertThat(ldapRepository.contains(ldapRepository.getUser(JAMES_USER_MAIL.asMailAddress()))).isTrue();
+            assertThat(ldapRepository.contains(ldapRepository.getUsername(JAMES_USER_MAIL.asMailAddress()))).isTrue();
         }
 
         private ReadOnlyUsersLDAPRepository startUsersRepository(HierarchicalConfiguration<ImmutableNode> ldapRepositoryConfiguration) throws Exception {
diff --git a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
index 09ec685..a5f056c 100644
--- a/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
+++ b/server/data/data-library/src/test/java/org/apache/james/user/lib/AbstractUsersRepositoryTest.java
@@ -236,7 +236,7 @@ public abstract class AbstractUsersRepositoryTest {
 
     @Test
     void getUserShouldBeCaseInsentive() throws Exception {
-        assertThat(usersRepository.getUser(user1CaseVariation.asMailAddress()))
+        assertThat(usersRepository.getUsername(user1CaseVariation.asMailAddress()))
             .isEqualTo(user1);
     }
 
@@ -457,7 +457,7 @@ public abstract class AbstractUsersRepositoryTest {
         // Some implementations do not support changing virtual hosting value
         Assumptions.assumeTrue(usersRepository.supportVirtualHosting());
 
-        assertThat(usersRepository.getUser(new MailAddress("local@domain"))).isEqualTo(Username.of("local@domain"));
+        assertThat(usersRepository.getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local@domain"));
     }
 
     @Test
@@ -467,7 +467,7 @@ public abstract class AbstractUsersRepositoryTest {
         // Some implementations do not support changing virtual hosting value
         Assumptions.assumeFalse(usersRepository.supportVirtualHosting());
 
-        assertThat(usersRepository.getUser(new MailAddress("local@domain"))).isEqualTo(Username.of("local"));
+        assertThat(usersRepository.getUsername(new MailAddress("local@domain"))).isEqualTo(Username.of("local"));
     }
 
     @Test
diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
index 9332ee3..9e76c1b 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/LocalResources.java
@@ -91,7 +91,7 @@ class LocalResources {
     }
 
     private boolean isLocaluser(MailAddress mailAddress) throws UsersRepositoryException {
-        return localUsers.contains(localUsers.getUser(mailAddress));
+        return localUsers.contains(localUsers.getUsername(mailAddress));
     }
 
     private boolean isLocalAlias(MailAddress mailAddress) throws UsersRepositoryException, RecipientRewriteTable.ErrorMappingException, RecipientRewriteTableException {
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SpamAssassin.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SpamAssassin.java
index e5959b4..4216832 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SpamAssassin.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SpamAssassin.java
@@ -107,7 +107,7 @@ public class SpamAssassin extends GenericMailet {
     }
 
     private void querySpamAssassin(Mail mail, MimeMessage message, SpamAssassinInvoker sa, MailAddress recipient) throws MessagingException, UsersRepositoryException {
-        SpamAssassinResult result = sa.scanMail(message, usersRepository.getUser(recipient));
+        SpamAssassinResult result = sa.scanMail(message, usersRepository.getUsername(recipient));
 
         // Add headers per recipient to mail object
         for (Attribute attribute : result.getHeadersAsAttributes()) {
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java
index d682065..dab2eac 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java
@@ -92,7 +92,7 @@ public class ToSenderFolder extends GenericMailet {
 
     private Username retrieveUser(MailAddress sender) throws MessagingException {
         try {
-            return usersRepository.getUser(sender);
+            return usersRepository.getUsername(sender);
         } catch (UsersRepositoryException e) {
             throw new MessagingException(e.getMessage());
         }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java
index 0bfc866..178b51a 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java
@@ -81,7 +81,7 @@ public class WithStorageDirective extends GenericMailet {
 
     public ThrowingConsumer<MailAddress> addStorageDirective(Mail mail) {
         return recipient -> {
-            AttributeName attributeNameForUser = AttributeName.of(MailStore.DELIVERY_PATH_PREFIX + usersRepository.getUser(recipient).asString());
+            AttributeName attributeNameForUser = AttributeName.of(MailStore.DELIVERY_PATH_PREFIX + usersRepository.getUsername(recipient).asString());
             mail.setAttribute(new Attribute(attributeNameForUser, targetFolderName));
         };
 
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java
index ce6391e..f1f0ed5 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java
@@ -110,7 +110,7 @@ public class SimpleMailStore implements MailStore {
 
     private Username computeUsername(MailAddress recipient) {
         try {
-            return usersRepository.getUser(recipient);
+            return usersRepository.getUsername(recipient);
         } catch (UsersRepositoryException e) {
             LOGGER.warn("Unable to retrieve username for {}", recipient.asPrettyString(), e);
             return Username.of(recipient.asString());
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ResourceLocator.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ResourceLocator.java
index be292f8..fd2648c 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ResourceLocator.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ResourceLocator.java
@@ -68,7 +68,7 @@ public class ResourceLocator {
 
     private Username retrieveUsername(MailAddress mailAddress) {
         try {
-            return usersRepository.getUser(mailAddress);
+            return usersRepository.getUsername(mailAddress);
         } catch (UsersRepositoryException e) {
             return Username.fromMailAddress(mailAddress);
         }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SievePoster.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SievePoster.java
index 23e7bd0..7e19c29 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SievePoster.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SievePoster.java
@@ -90,7 +90,7 @@ public class SievePoster implements Poster {
         String user = url.substring(startOfUser, endOfUser).toLowerCase(Locale.US);
         // Check if we should use the full email address as username
         try {
-            return usersRepository.getUser(new MailAddress(user, host));
+            return usersRepository.getUsername(new MailAddress(user, host));
         } catch (UsersRepositoryException e) {
             throw new MessagingException("Unable to accessUsersRepository", e);
         }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsOverQuota.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsOverQuota.java
index 3ea1148..921e227 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsOverQuota.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsOverQuota.java
@@ -72,7 +72,7 @@ public class IsOverQuota extends GenericMatcher {
         try {
             List<MailAddress> result = new ArrayList<>();
             for (MailAddress mailAddress : mail.getRecipients()) {
-                Username userName = usersRepository.getUser(mailAddress);
+                Username userName = usersRepository.getUsername(mailAddress);
                 MailboxPath mailboxPath = MailboxPath.inbox(userName);
                 QuotaRoot quotaRoot = quotaRootResolver.getQuotaRoot(mailboxPath);
 
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ResourceLocatorTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ResourceLocatorTest.java
index 270f161..8aebfe4 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ResourceLocatorTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/ResourceLocatorTest.java
@@ -55,7 +55,7 @@ public class ResourceLocatorTest {
     @Test(expected = ScriptNotFoundException.class)
     public void resourceLocatorImplShouldPropagateScriptNotFound() throws Exception {
         when(sieveRepository.getActive(USERNAME)).thenThrow(new ScriptNotFoundException());
-        when(usersRepository.getUser(mailAddress)).thenReturn(Username.of(RECEIVER_LOCALHOST));
+        when(usersRepository.getUsername(mailAddress)).thenReturn(Username.of(RECEIVER_LOCALHOST));
 
         resourceLocator.get(mailAddress);
     }
@@ -64,7 +64,7 @@ public class ResourceLocatorTest {
     public void resourceLocatorImplShouldWork() throws Exception {
         InputStream inputStream = new ByteArrayInputStream(new byte[0]);
         when(sieveRepository.getActive(USERNAME)).thenReturn(inputStream);
-        when(usersRepository.getUser(mailAddress)).thenReturn(Username.of(RECEIVER_LOCALHOST));
+        when(usersRepository.getUsername(mailAddress)).thenReturn(Username.of(RECEIVER_LOCALHOST));
 
         assertThat(resourceLocator.get(mailAddress).getScriptContent()).isEqualTo(inputStream);
     }
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java
index ccbb2d2..9c546ed 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java
@@ -85,7 +85,7 @@ public class LocalDeliveryTest {
         MessageManager messageManager = mock(MessageManager.class);
 
         when(usersRepository.supportVirtualHosting()).thenReturn(true);
-        when(usersRepository.getUser(new MailAddress(username.asString()))).thenReturn(username);
+        when(usersRepository.getUsername(new MailAddress(username.asString()))).thenReturn(username);
         when(mailboxManager.getMailbox(eq(inbox), any(MailboxSession.class))).thenReturn(messageManager);
         when(session.getUser()).thenReturn(username);
 
@@ -105,8 +105,8 @@ public class LocalDeliveryTest {
         MailboxPath inbox = MailboxPath.inbox(username);
         MessageManager messageManager = mock(MessageManager.class);
         when(usersRepository.supportVirtualHosting()).thenReturn(false);
-        when(usersRepository.getUser(new MailAddress("receiver@localhost"))).thenReturn(username);
-        when(usersRepository.getUser(new MailAddress(RECEIVER_DOMAIN_COM))).thenReturn(username);
+        when(usersRepository.getUsername(new MailAddress("receiver@localhost"))).thenReturn(username);
+        when(usersRepository.getUsername(new MailAddress(RECEIVER_DOMAIN_COM))).thenReturn(username);
         when(mailboxManager.getMailbox(eq(inbox), any(MailboxSession.class))).thenReturn(messageManager);
         when(session.getUser()).thenReturn(username);
 
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java
index a7a0aea..ee72e3a 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java
@@ -92,7 +92,7 @@ public class SieveIntegrationTest {
     @Test
     public void serviceShouldNotModifyEmailWhenErrorRetrievingScript() throws Exception {
         when(usersRepository.supportVirtualHosting()).thenReturn(true);
-        when(usersRepository.getUser(new MailAddress(RECEIVER_DOMAIN_COM))).thenReturn(Username.of(RECEIVER_DOMAIN_COM));
+        when(usersRepository.getUsername(new MailAddress(RECEIVER_DOMAIN_COM))).thenReturn(Username.of(RECEIVER_DOMAIN_COM));
         when(resourceLocator.get(new MailAddress(RECEIVER_DOMAIN_COM))).thenThrow(new ScriptNotFoundException());
 
         FakeMail mail = createMail();
@@ -106,7 +106,7 @@ public class SieveIntegrationTest {
     public void mailShouldBeWellDeliveredByDefaultToUserWhenVirtualHostingIsTurnedOn() throws Exception {
         prepareTestUsingScript("org/apache/james/transport/mailets/delivery/keep.script");
         when(usersRepository.supportVirtualHosting()).thenReturn(true);
-        when(usersRepository.getUser(new MailAddress(RECEIVER_DOMAIN_COM))).thenReturn(Username.of(RECEIVER_DOMAIN_COM));
+        when(usersRepository.getUsername(new MailAddress(RECEIVER_DOMAIN_COM))).thenReturn(Username.of(RECEIVER_DOMAIN_COM));
 
         FakeMail mail = createMail();
         testee.service(mail);
@@ -118,7 +118,7 @@ public class SieveIntegrationTest {
     public void mailShouldBeWellDeliveredByDefaultToUserWhenvirtualHostingIsTurnedOff() throws Exception {
         prepareTestUsingScript("org/apache/james/transport/mailets/delivery/keep.script");
         when(usersRepository.supportVirtualHosting()).thenReturn(false);
-        when(usersRepository.getUser(new MailAddress("receiver@localhost"))).thenReturn(Username.of("receiver"));
+        when(usersRepository.getUsername(new MailAddress("receiver@localhost"))).thenReturn(Username.of("receiver"));
 
         FakeMail mail = createMail();
         testee.service(mail);
@@ -959,8 +959,8 @@ public class SieveIntegrationTest {
 
     private void prepareTestUsingScriptAndDates(String script, ZonedDateTime scriptCreationDate, ZonedDateTime scriptExecutionDate) throws Exception {
         when(usersRepository.supportVirtualHosting()).thenReturn(false);
-        when(usersRepository.getUser(new MailAddress(LOCAL_PART + "@localhost"))).thenReturn(Username.of(LOCAL_PART));
-        when(usersRepository.getUser(new MailAddress(LOCAL_PART + "@domain.com"))).thenReturn(Username.of(LOCAL_PART));
+        when(usersRepository.getUsername(new MailAddress(LOCAL_PART + "@localhost"))).thenReturn(Username.of(LOCAL_PART));
+        when(usersRepository.getUsername(new MailAddress(LOCAL_PART + "@domain.com"))).thenReturn(Username.of(LOCAL_PART));
         when(resourceLocator.get(new MailAddress(RECEIVER_DOMAIN_COM))).thenReturn(new ResourceLocator.UserSieveInformation(scriptCreationDate,
             scriptExecutionDate,
             ClassLoader.getSystemResourceAsStream(script)));
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java
index 00ca494..3155b6e 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java
@@ -67,7 +67,7 @@ public class SimpleMailStoreTest {
     @Test
     public void storeMailShouldUseFullMailAddressWhenSupportsVirtualHosting() throws Exception {
         MailAddress recipient = MailAddressFixture.OTHER_AT_JAMES;
-        when(usersRepository.getUser(recipient)).thenReturn(Username.of(recipient.asString()));
+        when(usersRepository.getUsername(recipient)).thenReturn(Username.of(recipient.asString()));
         FakeMail mail = FakeMail.builder()
             .name("name")
             .mimeMessage(mimeMessage)
@@ -80,7 +80,7 @@ public class SimpleMailStoreTest {
     @Test
     public void storeMailShouldUseLocalPartWhenSupportsVirtualHosting() throws Exception {
         MailAddress recipient = MailAddressFixture.OTHER_AT_JAMES;
-        when(usersRepository.getUser(recipient)).thenReturn(Username.of(recipient.getLocalPart()));
+        when(usersRepository.getUsername(recipient)).thenReturn(Username.of(recipient.getLocalPart()));
         FakeMail mail = FakeMail.builder()
             .name("name")
             .mimeMessage(mimeMessage)
@@ -93,7 +93,7 @@ public class SimpleMailStoreTest {
     @Test
     public void storeMailShouldUseFullMailAddressWhenErrorReadingUsersRepository() throws Exception {
         MailAddress recipient = MailAddressFixture.OTHER_AT_JAMES;
-        when(usersRepository.getUser(recipient)).thenThrow(new UsersRepositoryException("Any message"));
+        when(usersRepository.getUsername(recipient)).thenThrow(new UsersRepositoryException("Any message"));
         FakeMail mail = FakeMail.builder()
             .name("name")
             .mimeMessage(mimeMessage)
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/ToRecipientFolderTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/ToRecipientFolderTest.java
index 6b3b249..00c6d9b 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/ToRecipientFolderTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/ToRecipientFolderTest.java
@@ -127,7 +127,7 @@ public class ToRecipientFolderTest {
     @Test
     public void folderParameterShouldIndicateDestinationFolder() throws Exception {
         when(usersRepository.supportVirtualHosting()).thenReturn(true);
-        when(usersRepository.getUser(new MailAddress(USER))).thenReturn(USERNAME);
+        when(usersRepository.getUsername(new MailAddress(USER))).thenReturn(USERNAME);
         when(mailboxManager.getMailbox(eq(JUNK_VIRTUAL_HOSTING), any(MailboxSession.class))).thenReturn(messageManager);
 
         testee.init(FakeMailetConfig.builder()
@@ -143,7 +143,7 @@ public class ToRecipientFolderTest {
     @Test
     public void folderParameterShouldBeInboxByDefault() throws Exception {
         when(usersRepository.supportVirtualHosting()).thenReturn(true);
-        when(usersRepository.getUser(new MailAddress(USER))).thenReturn(USERNAME);
+        when(usersRepository.getUsername(new MailAddress(USER))).thenReturn(USERNAME);
         when(mailboxManager.getMailbox(eq(INBOX), any(MailboxSession.class))).thenReturn(messageManager);
 
         testee.init(FakeMailetConfig.builder()
@@ -158,8 +158,8 @@ public class ToRecipientFolderTest {
     @Test
     public void folderParameterShouldWorkWhenVirtualHostingIsTurnedOff() throws Exception {
         when(usersRepository.supportVirtualHosting()).thenReturn(false);
-        when(usersRepository.getUser(new MailAddress(USER_LOCAL_PART + "@localhost"))).thenReturn(USERNAME_LOCAL_PART);
-        when(usersRepository.getUser(new MailAddress(USER))).thenReturn(USERNAME_LOCAL_PART);
+        when(usersRepository.getUsername(new MailAddress(USER_LOCAL_PART + "@localhost"))).thenReturn(USERNAME_LOCAL_PART);
+        when(usersRepository.getUsername(new MailAddress(USER))).thenReturn(USERNAME_LOCAL_PART);
         when(mailboxManager.getMailbox(eq(JUNK), any(MailboxSession.class))).thenReturn(messageManager);
         when(session.getUser()).thenReturn(Username.of(USER_LOCAL_PART));
 
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/IsOverQuotaTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/IsOverQuotaTest.java
index b96a68c..34b39b0 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/IsOverQuotaTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/IsOverQuotaTest.java
@@ -59,8 +59,8 @@ public class IsOverQuotaTest {
 
         testee.init(FakeMatcherConfig.builder().matcherName("IsOverQuota").build());
 
-        when(usersRepository.getUser(MailAddressFixture.ANY_AT_JAMES)).thenReturn(Username.of(MailAddressFixture.ANY_AT_JAMES.getLocalPart()));
-        when(usersRepository.getUser(MailAddressFixture.OTHER_AT_JAMES)).thenReturn(Username.of(MailAddressFixture.OTHER_AT_JAMES.getLocalPart()));
+        when(usersRepository.getUsername(MailAddressFixture.ANY_AT_JAMES)).thenReturn(Username.of(MailAddressFixture.ANY_AT_JAMES.getLocalPart()));
+        when(usersRepository.getUsername(MailAddressFixture.OTHER_AT_JAMES)).thenReturn(Username.of(MailAddressFixture.OTHER_AT_JAMES.getLocalPart()));
     }
 
     @Test
@@ -148,8 +148,8 @@ public class IsOverQuotaTest {
 
     @Test
     public void matchShouldSupportVirtualHosting() throws Exception {
-        when(usersRepository.getUser(MailAddressFixture.ANY_AT_JAMES)).thenReturn(Username.of(MailAddressFixture.ANY_AT_JAMES.asString()));
-        when(usersRepository.getUser(MailAddressFixture.OTHER_AT_JAMES)).thenReturn(Username.of(MailAddressFixture.OTHER_AT_JAMES.asString()));
+        when(usersRepository.getUsername(MailAddressFixture.ANY_AT_JAMES)).thenReturn(Username.of(MailAddressFixture.ANY_AT_JAMES.asString()));
+        when(usersRepository.getUsername(MailAddressFixture.OTHER_AT_JAMES)).thenReturn(Username.of(MailAddressFixture.OTHER_AT_JAMES.asString()));
         Username username = Username.of(MailAddressFixture.ANY_AT_JAMES.asString());
         QuotaRoot quotaRoot = quotaRootResolver.getQuotaRoot(MailboxPath.inbox(username));
         maxQuotaManager.setMaxStorage(quotaRoot, QuotaSizeLimit.size(100));
diff --git a/server/protocols/fetchmail/src/main/java/org/apache/james/fetchmail/MessageProcessor.java b/server/protocols/fetchmail/src/main/java/org/apache/james/fetchmail/MessageProcessor.java
index 49c374b..e16a8d8 100644
--- a/server/protocols/fetchmail/src/main/java/org/apache/james/fetchmail/MessageProcessor.java
+++ b/server/protocols/fetchmail/src/main/java/org/apache/james/fetchmail/MessageProcessor.java
@@ -842,7 +842,7 @@ public class MessageProcessor extends ProcessorAbstract {
         // the recipient in respect of this
         // See JAMES-1135
         return isLocalServer(recipient)
-            && getLocalUsers().contains(getLocalUsers().getUser(recipient));
+            && getLocalUsers().contains(getLocalUsers().getUsername(recipient));
     }
 
     /**
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/ExtractMDNOriginalJMAPMessageId.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/ExtractMDNOriginalJMAPMessageId.java
index 30fc5ef..1679fd9 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/ExtractMDNOriginalJMAPMessageId.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/ExtractMDNOriginalJMAPMessageId.java
@@ -102,7 +102,7 @@ public class ExtractMDNOriginalJMAPMessageId extends GenericMailet {
     private Optional<MessageId> findMessageIdForRFC822MessageId(String messageId, MailAddress recipient) {
         LOGGER.debug("Searching message {} for recipient {}", messageId, recipient.asPrettyString());
         try {
-            MailboxSession session = mailboxManager.createSystemSession(usersRepository.getUser(recipient));
+            MailboxSession session = mailboxManager.createSystemSession(usersRepository.getUsername(recipient));
             int limit = 1;
             MultimailboxesSearchQuery searchByRFC822MessageId = MultimailboxesSearchQuery
                 .from(new SearchQuery(SearchQuery.mimeMessageID(messageId)))
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/JMAPFiltering.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/JMAPFiltering.java
index 85a09bc..0a0d58f 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/JMAPFiltering.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/mailet/filter/JMAPFiltering.java
@@ -88,7 +88,7 @@ public class JMAPFiltering extends GenericMailet {
 
     private Optional<Username> retrieveUser(MailAddress recipient) {
         try {
-            return Optional.ofNullable(usersRepository.getUser(recipient));
+            return Optional.ofNullable(usersRepository.getUsername(recipient));
         } catch (UsersRepositoryException e) {
             logger.error("cannot retrieve user " + recipient.asString(), e);
             return Optional.empty();
diff --git a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/hook/MailboxDeliverToRecipientHandler.java b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/hook/MailboxDeliverToRecipientHandler.java
index 15419ef..e1bc470 100644
--- a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/hook/MailboxDeliverToRecipientHandler.java
+++ b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/hook/MailboxDeliverToRecipientHandler.java
@@ -63,7 +63,7 @@ public class MailboxDeliverToRecipientHandler implements DeliverToRecipientHook
     @Override
     public HookResult deliver(SMTPSession session, MailAddress recipient, MailEnvelope envelope) {
         try {
-            Username username = users.getUser(recipient);
+            Username username = users.getUsername(recipient);
 
             MailboxSession mailboxSession = mailboxManager.createSystemSession(username);
             MailboxPath inbox = MailboxPath.inbox(mailboxSession);
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SenderAuthIdentifyVerificationRcptHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SenderAuthIdentifyVerificationRcptHook.java
index 63d98c7..cf6924c 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SenderAuthIdentifyVerificationRcptHook.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SenderAuthIdentifyVerificationRcptHook.java
@@ -70,7 +70,7 @@ public class SenderAuthIdentifyVerificationRcptHook extends AbstractSenderAuthId
     @Override
     protected Username getUser(MailAddress mailAddress) {
         try {
-            return users.getUser(mailAddress);
+            return users.getUsername(mailAddress);
         } catch (UsersRepositoryException e) {
             throw new RuntimeException(e);
         }
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/ValidRcptHandler.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/ValidRcptHandler.java
index dbc20e1..c6bcd73 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/ValidRcptHandler.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/ValidRcptHandler.java
@@ -65,7 +65,7 @@ public class ValidRcptHandler extends AbstractValidRcptHandler implements Protoc
     @Override
     protected boolean isValidRecipient(SMTPSession session, MailAddress recipient) {
         try {
-            Username username = users.getUser(recipient);
+            Username username = users.getUsername(recipient);
 
             if (users.contains(username)) {
                 return true;
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/AliasRoutes.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/AliasRoutes.java
index 8905b3b..39d82b6 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/AliasRoutes.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/AliasRoutes.java
@@ -184,7 +184,7 @@ public class AliasRoutes implements Routes {
     }
 
     private void ensureUserDoesNotExist(MailAddress mailAddress) throws UsersRepositoryException {
-        Username username = usersRepository.getUser(mailAddress);
+        Username username = usersRepository.getUsername(mailAddress);
 
         if (usersRepository.contains(username)) {
             throw ErrorResponder.builder()
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/ForwardRoutes.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/ForwardRoutes.java
index 34908d7..c5cc581 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/ForwardRoutes.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/ForwardRoutes.java
@@ -173,7 +173,7 @@ public class ForwardRoutes implements Routes {
     }
 
     private void ensureUserExist(MailAddress mailAddress) throws UsersRepositoryException {
-        if (!usersRepository.contains(usersRepository.getUser(mailAddress))) {
+        if (!usersRepository.contains(usersRepository.getUsername(mailAddress))) {
             throw ErrorResponder.builder()
                 .statusCode(HttpStatus.NOT_FOUND_404)
                 .type(ErrorType.INVALID_ARGUMENT)
diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/GroupsRoutes.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/GroupsRoutes.java
index d0fc4e9..87de8c9 100644
--- a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/GroupsRoutes.java
+++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/GroupsRoutes.java
@@ -168,7 +168,7 @@ public class GroupsRoutes implements Routes {
     }
 
     private void ensureNotShadowingAnotherAddress(MailAddress groupAddress) throws UsersRepositoryException {
-        if (usersRepository.contains(usersRepository.getUser(groupAddress))) {
+        if (usersRepository.contains(usersRepository.getUsername(groupAddress))) {
             throw ErrorResponder.builder()
                 .statusCode(HttpStatus.CONFLICT_409)
                 .type(ErrorType.INVALID_ARGUMENT)


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 08/08: JAMES-3105 Limit concurrency of mailbox counters recomputation

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit f49b5b06a7a01af46d921a276b95beb334289c14
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Mar 20 10:53:46 2020 +0700

    JAMES-3105 Limit concurrency of mailbox counters recomputation
---
 .../cassandra/mail/task/RecomputeMailboxCountersService.java       | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersService.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersService.java
index b057c93..e14d16e 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersService.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersService.java
@@ -52,6 +52,9 @@ public class RecomputeMailboxCountersService {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(RecomputeMailboxCountersService.class);
 
+    private static final int MAILBOX_CONCURRENCY = 2;
+    private static final int MESSAGE_CONCURRENCY = 8;
+
     private static class Counter {
         private final CassandraId mailboxId;
         private final AtomicLong total;
@@ -162,7 +165,7 @@ public class RecomputeMailboxCountersService {
 
     Mono<Result> recomputeMailboxCounters(Context context) {
         return mailboxDAO.retrieveAllMailboxes()
-            .flatMap(mailbox -> recomputeMailboxCounter(context, mailbox))
+            .flatMap(mailbox -> recomputeMailboxCounter(context, mailbox), MAILBOX_CONCURRENCY)
             .reduce(Result.COMPLETED, Task::combine)
             .onErrorResume(e -> {
                 LOGGER.error("Error listing mailboxes", e);
@@ -175,7 +178,7 @@ public class RecomputeMailboxCountersService {
         Counter counter = new Counter(mailboxId);
 
         return imapUidToMessageIdDAO.retrieveMessages(mailboxId, MessageRange.all())
-            .flatMap(message -> latestMetadata(mailboxId, message))
+            .flatMap(message -> latestMetadata(mailboxId, message), MESSAGE_CONCURRENCY)
             .doOnNext(counter::process)
             .then(Mono.defer(() -> counterDAO.resetCounters(counter.snapshot())))
             .then(Mono.just(Result.COMPLETED))


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 01/08: Upgrade play-json to 2.8

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 058a83fa109eb36e9508606988ef3453ea3514ac
Author: Matthieu Baechler <ma...@apache.org>
AuthorDate: Thu Mar 19 10:51:34 2020 +0100

    Upgrade play-json to 2.8
---
 mailbox/event/json/pom.xml                                         | 4 ++--
 .../main/scala/org/apache/james/event/json/EventSerializer.scala   | 6 ++++--
 .../test/java/org/apache/james/event/json/dtos/QuotaCountTest.java | 6 +++---
 .../test/java/org/apache/james/event/json/dtos/QuotaSizeTest.java  | 7 ++++---
 4 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/mailbox/event/json/pom.xml b/mailbox/event/json/pom.xml
index bfd77a5..6b391ee 100644
--- a/mailbox/event/json/pom.xml
+++ b/mailbox/event/json/pom.xml
@@ -60,7 +60,7 @@
         <dependency>
             <groupId>com.typesafe.play</groupId>
             <artifactId>play-json_${scala.base}</artifactId>
-            <version>2.7.4</version>
+            <version>2.8.1</version>
         </dependency>
         <dependency>
             <groupId>net.javacrumbs.json-unit</groupId>
@@ -70,7 +70,7 @@
         <dependency>
             <groupId>org.julienrf</groupId>
             <artifactId>play-json-derived-codecs_${scala.base}</artifactId>
-            <version>6.0.0</version>
+            <version>7.0.0</version>
         </dependency>
         <dependency>
             <groupId>org.scala-lang</groupId>
diff --git a/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala b/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
index bf0bc87..4c7a2a2 100644
--- a/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
+++ b/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
@@ -205,9 +205,11 @@ class JsonSerialize(mailboxIdFactory: MailboxId.Factory, messageIdFactory: Messa
   implicit val systemFlagsWrites: Writes[SystemFlag] = Writes.enumNameWrites
   implicit val userWriters: Writes[Username] = (user: Username) => JsString(user.asString)
   implicit val quotaRootWrites: Writes[QuotaRoot] = quotaRoot => JsString(quotaRoot.getValue)
-  implicit val quotaUsageValueWrites: Writes[QuotaUsageValue[_, _]] = value => JsNumber(value.asLong())
-  implicit val quotaLimitValueWrites: Writes[QuotaLimitValue[_]] = value => if (value.isUnlimited) JsNull else JsNumber(value.asLong())
   implicit val quotaScopeWrites: Writes[JavaQuota.Scope] = value => JsString(value.name)
+  implicit val quotaCountLimitWrites: Writes[QuotaCountLimit] = value => if (value.isUnlimited) JsNull else JsNumber(value.asLong())
+  implicit val quotaCountUsageWrites: Writes[QuotaCountUsage] = value => JsNumber(value.asLong())
+  implicit val quotaSizeLimitWrites: Writes[QuotaSizeLimit] = value => if (value.isUnlimited) JsNull else JsNumber(value.asLong())
+  implicit val quotaSizeUsageWrites: Writes[QuotaSizeUsage] = value => JsNumber(value.asLong())
   implicit val quotaCountWrites: Writes[Quota[QuotaCountLimit, QuotaCountUsage]] = Json.writes[Quota[QuotaCountLimit, QuotaCountUsage]]
   implicit val quotaSizeWrites: Writes[Quota[QuotaSizeLimit, QuotaSizeUsage]] = Json.writes[Quota[QuotaSizeLimit, QuotaSizeUsage]]
   implicit val mailboxPathWrites: Writes[MailboxPath] = Json.writes[MailboxPath]
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/dtos/QuotaCountTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/dtos/QuotaCountTest.java
index 43cb574..5b06266 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/dtos/QuotaCountTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/dtos/QuotaCountTest.java
@@ -41,7 +41,7 @@ import scala.math.BigDecimal;
 class QuotaCountTest {
     @Test
     void quotaCountLimitShouldBeWellSerialized() {
-        assertThat(DTO_JSON_SERIALIZE.quotaLimitValueWrites().writes(QuotaCountLimit.count(18)))
+        assertThat(DTO_JSON_SERIALIZE.quotaCountLimitWrites().writes(QuotaCountLimit.count(18)))
             .isEqualTo(new JsNumber(BigDecimal.valueOf(18)));
     }
 
@@ -53,7 +53,7 @@ class QuotaCountTest {
 
     @Test
     void quotaCountLimitShouldBeWellSerializedWhenUnlimited() {
-        assertThat(DTO_JSON_SERIALIZE.quotaLimitValueWrites().writes(QuotaCountLimit.unlimited()))
+        assertThat(DTO_JSON_SERIALIZE.quotaCountLimitWrites().writes(QuotaCountLimit.unlimited()))
             .isEqualTo(JsNull$.MODULE$);
     }
 
@@ -71,7 +71,7 @@ class QuotaCountTest {
 
     @Test
     void quotaCountUsageShouldBeWellSerialized() {
-        assertThat(DTO_JSON_SERIALIZE.quotaUsageValueWrites().writes(QuotaCountUsage.count(18)))
+        assertThat(DTO_JSON_SERIALIZE.quotaCountUsageWrites().writes(QuotaCountUsage.count(18)))
             .isEqualTo(new JsNumber(BigDecimal.valueOf(18)));
     }
 
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/dtos/QuotaSizeTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/dtos/QuotaSizeTest.java
index cdb800b..e19ec08 100644
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/dtos/QuotaSizeTest.java
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/dtos/QuotaSizeTest.java
@@ -38,9 +38,10 @@ import play.api.libs.json.Json;
 import scala.math.BigDecimal;
 
 class QuotaSizeTest {
+
     @Test
     void quotaSizeLimitShouldBeWellSerialized() {
-        assertThat(DTO_JSON_SERIALIZE.quotaLimitValueWrites().writes(QuotaSizeLimit.size(18)))
+        assertThat(DTO_JSON_SERIALIZE.quotaSizeLimitWrites().writes(QuotaSizeLimit.size(18)))
             .isEqualTo(new JsNumber(BigDecimal.valueOf(18)));
     }
 
@@ -52,7 +53,7 @@ class QuotaSizeTest {
 
     @Test
     void quotaSizeLimitShouldBeWellSerializedWhenUnlimited() {
-        assertThat(DTO_JSON_SERIALIZE.quotaLimitValueWrites().writes(QuotaSizeLimit.unlimited()))
+        assertThat(DTO_JSON_SERIALIZE.quotaSizeLimitWrites().writes(QuotaSizeLimit.unlimited()))
             .isEqualTo(JsNull$.MODULE$);
     }
 
@@ -70,7 +71,7 @@ class QuotaSizeTest {
 
     @Test
     void quotaSizeUsageShouldBeWellSerialized() {
-        assertThat(DTO_JSON_SERIALIZE.quotaUsageValueWrites().writes(QuotaSizeUsage.size(18)))
+        assertThat(DTO_JSON_SERIALIZE.quotaSizeUsageWrites().writes(QuotaSizeUsage.size(18)))
             .isEqualTo(new JsNumber(BigDecimal.valueOf(18)));
     }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


[james-project] 02/08: JAMES-3119 Strong type ProtocolSession

Posted by bt...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 58b1d879abfd679758c95725375ab3f7f5598af7
Author: Gautier DI FOLCO <gd...@linagora.com>
AuthorDate: Wed Mar 18 13:08:57 2020 +0100

    JAMES-3119 Strong type ProtocolSession
---
 .../james/protocols/api/ProtocolSession.java       | 83 +++++++++++++++++++---
 .../james/protocols/api/ProtocolSessionImpl.java   | 45 +++++++-----
 .../james/protocols/api/ProtocolSessionTest.java   | 22 +++---
 .../lmtp/core/DataLineMessageHookHandler.java      |  4 +-
 .../apache/james/protocols/pop3/POP3Session.java   | 11 ++-
 .../pop3/core/AbstractApopCmdHandler.java          |  7 +-
 .../james/protocols/pop3/core/DeleCmdHandler.java  |  8 ++-
 .../james/protocols/pop3/core/ListCmdHandler.java  | 11 +--
 .../protocols/pop3/core/MessageMetaDataUtils.java  | 12 ++--
 .../james/protocols/pop3/core/QuitCmdHandler.java  |  4 +-
 .../james/protocols/pop3/core/RetrCmdHandler.java  |  5 +-
 .../james/protocols/pop3/core/RsetCmdHandler.java  |  2 +-
 .../james/protocols/pop3/core/StatCmdHandler.java  | 10 +--
 .../james/protocols/pop3/core/TopCmdHandler.java   |  4 +-
 .../james/protocols/pop3/core/UidlCmdHandler.java  |  8 +--
 .../apache/james/protocols/smtp/SMTPSession.java   | 13 ++--
 .../james/protocols/smtp/SMTPSessionImpl.java      | 22 ++----
 .../smtp/core/AbstractAddHeadersFilter.java        |  9 +--
 ...ractSenderAuthIdentifyVerificationRcptHook.java |  2 +-
 .../james/protocols/smtp/core/DataCmdHandler.java  | 14 ++--
 .../smtp/core/DataLineMessageHookHandler.java      | 20 ++++--
 .../james/protocols/smtp/core/MailCmdHandler.java  | 20 +++---
 .../james/protocols/smtp/core/RcptCmdHandler.java  | 31 ++++----
 .../smtp/core/ReceivedDataLineFilter.java          | 18 +++--
 .../smtp/core/SeparatingDataLineFilter.java        |  5 +-
 .../protocols/smtp/core/UnknownCmdHandler.java     |  7 +-
 .../smtp/core/esmtp/MailSizeEsmtpExtension.java    | 29 ++++----
 .../smtp/core/fastfail/DNSRBLHandler.java          | 21 +++---
 .../smtp/core/fastfail/MaxUnknownCmdHandler.java   | 13 ++--
 .../core/fastfail/ResolvableEhloHeloHandler.java   | 12 ++--
 .../core/fastfail/SupressDuplicateRcptHandler.java | 38 +++++-----
 .../smtp/core/fastfail/DNSRBLHandlerTest.java      | 73 ++++++++++---------
 .../smtp/core/fastfail/MaxRcptHandlerTest.java     |  4 +-
 .../core/fastfail/MaxUnknownCmdHandlerTest.java    | 32 ++++++---
 .../fastfail/ResolvableEhloHeloHandlerTest.java    | 60 +++++++++-------
 .../fastfail/ValidSenderDomainHandlerTest.java     | 35 +++++----
 .../protocols/smtp/utils/BaseFakeSMTPSession.java  | 14 ++--
 .../DataLineJamesMessageHookHandler.java           | 11 +--
 .../org/apache/james/smtpserver/SMTPConstants.java |  8 ++-
 .../james/smtpserver/fastfail/SPFHandler.java      | 29 ++++----
 .../james/smtpserver/fastfail/URIRBLHandler.java   | 18 ++---
 .../netty/SMTPChannelUpstreamHandler.java          |  4 +-
 .../apache/james/smtpserver/SPFHandlerTest.java    | 41 +++++++----
 .../james/smtpserver/SpamAssassinHandlerTest.java  | 41 +++++++----
 .../apache/james/smtpserver/URIRBLHandlerTest.java | 41 +++++++----
 .../james/smtpserver/ValidRcptHandlerTest.java     | 39 ++++++----
 .../apache/james/smtpserver/ValidRcptMXTest.java   | 38 ++++++----
 upgrade-instructions.md                            | 18 +++++
 48 files changed, 614 insertions(+), 402 deletions(-)

diff --git a/protocols/api/src/main/java/org/apache/james/protocols/api/ProtocolSession.java b/protocols/api/src/main/java/org/apache/james/protocols/api/ProtocolSession.java
index 0937b4b..b483985 100644
--- a/protocols/api/src/main/java/org/apache/james/protocols/api/ProtocolSession.java
+++ b/protocols/api/src/main/java/org/apache/james/protocols/api/ProtocolSession.java
@@ -22,10 +22,16 @@ package org.apache.james.protocols.api;
 import java.net.InetSocketAddress;
 import java.nio.charset.Charset;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
 
 import org.apache.james.core.Username;
 import org.apache.james.protocols.api.handler.LineHandler;
 
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
 /**
  * Session for a protocol. Every new connection generates a new session
  */
@@ -36,16 +42,75 @@ public interface ProtocolSession {
         Transaction
     }
 
+    class AttachmentKey<T> {
+        public static <U> AttachmentKey<U> of(String value, Class<U> type) {
+            Preconditions.checkArgument(!Strings.isNullOrEmpty(value), "An attachment key should not be empty or null");
+
+            return new AttachmentKey<>(value, type);
+        }
+
+        private final String value;
+        private final Class<T> type;
+
+        private AttachmentKey(String value, Class<T> type) {
+            this.value = value;
+            this.type = type;
+        }
+
+        public String asString() {
+            return value;
+        }
+
+        public Optional<T> convert(Object object) {
+            return Optional.ofNullable(object)
+                .filter(type::isInstance)
+                .map(type::cast);
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof AttachmentKey) {
+                AttachmentKey<?> that = (AttachmentKey<?>) o;
+
+                return Objects.equals(this.value, that.value)
+                    && Objects.equals(this.type, that.type);
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(value, type);
+        }
+
+        @Override
+        public String toString() {
+            return MoreObjects.toStringHelper(this)
+                .add("value", value)
+                .add("type", type.getName())
+                .toString();
+        }
+    }
+
     /**
-     * Store the given value with the given key in the specified {@link State}. If you want to remove a value you need to use <code>null</code> as value
+     * Store the given value with the given key in the specified {@link State}.
      * 
      * @param key the key under which the value should get stored
-     * @param value the value which will get stored under the given key or <code>null</code> if you want to remove any value which is stored under the key
+     * @param value the value which will get stored under the given key
      * @param state the {@link State} to which the mapping belongs
      * @return oldValue the value which was stored before for this key or <code>null</code> if non was stored before.
      */
-    Object setAttachment(String key, Object value, State state);
-    
+    <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state);
+
+    /**
+     * Remove a value stored for the given key in the specified {@link State}.
+     *
+     * @param key the key under which the value should get stored
+     * @param state the {@link State} to which the mapping belongs
+     * @return oldValue the value which was stored before for this key or <code>null</code> if non was stored before.
+     */
+    <T> Optional<T> removeAttachment(AttachmentKey<T> key,State state);
+
     /**
      * Return the value which is stored for the given key in the specified {@link State} or <code>null</code> if non was stored before.
      * 
@@ -53,27 +118,27 @@ public interface ProtocolSession {
      * @param state the {@link State} in which the value was stored for the key
      * @return value the stored value for the key
      */
-    Object getAttachment(String key, State state);
+    <T> Optional<T> getAttachment(AttachmentKey<T> key, State state);
     
     
     /**
      * Return Map which can be used to store objects within a session
      * 
      * @return state
-     * @deprecated use {@link #setAttachment(String, Object, State)}
+     * @deprecated use {@link #setAttachment(AttachmentKey, Object, State)}
      */
     @Deprecated
-    Map<String, Object> getState();
+    Map<AttachmentKey<?>, Object> getState();
     
     
     /**
      * Returns Map that consists of the state of the {@link ProtocolSession} per connection
      *
      * @return map of the current {@link ProtocolSession} state per connection
-     * @deprecated use {@link #getAttachment(String, State)}
+     * @deprecated use {@link #getAttachment(AttachmentKey, State)}
      */
     @Deprecated
-    Map<String,Object> getConnectionState();
+    Map<AttachmentKey<?>, Object> getConnectionState();
 
     
     /**
diff --git a/protocols/api/src/main/java/org/apache/james/protocols/api/ProtocolSessionImpl.java b/protocols/api/src/main/java/org/apache/james/protocols/api/ProtocolSessionImpl.java
index 266aeba..ec27d9e 100644
--- a/protocols/api/src/main/java/org/apache/james/protocols/api/ProtocolSessionImpl.java
+++ b/protocols/api/src/main/java/org/apache/james/protocols/api/ProtocolSessionImpl.java
@@ -23,10 +23,13 @@ import java.net.InetSocketAddress;
 import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.james.core.Username;
 import org.apache.james.protocols.api.handler.LineHandler;
 
+import com.google.common.base.Preconditions;
+
 /**
  * Basic implementation of {@link ProtocolSession}
  * 
@@ -34,8 +37,8 @@ import org.apache.james.protocols.api.handler.LineHandler;
  */
 public class ProtocolSessionImpl implements ProtocolSession {
     private final ProtocolTransport transport;
-    private final Map<String, Object> connectionState;
-    private final Map<String, Object> sessionState;
+    private final Map<AttachmentKey<?>, Object> connectionState;
+    private final Map<AttachmentKey<?>, Object> sessionState;
     private Username username;
     protected final ProtocolConfiguration config;
     private static final Charset CHARSET = Charset.forName("US-ASCII");
@@ -92,12 +95,12 @@ public class ProtocolSessionImpl implements ProtocolSession {
     
     
     @Override
-    public Map<String, Object> getConnectionState() {
+    public Map<AttachmentKey<?>, Object> getConnectionState() {
         return connectionState;
     }
 
     @Override
-    public Map<String, Object> getState() {
+    public Map<AttachmentKey<?>, Object> getState() {
         return sessionState;
     }
 
@@ -134,28 +137,34 @@ public class ProtocolSessionImpl implements ProtocolSession {
     }
 
     @Override
-    public Object setAttachment(String key, Object value, State state) {
+    public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
+        Preconditions.checkNotNull(key, "key cannot be null");
+        Preconditions.checkNotNull(value, "value cannot be null");
+
+        if (state == State.Connection) {
+            return key.convert(connectionState.put(key, value));
+        } else {
+            return key.convert(sessionState.put(key, value));
+        }
+    }
+
+    @Override
+    public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+        Preconditions.checkNotNull(key, "key cannot be null");
+
         if (state == State.Connection) {
-            if (value == null) {
-                return connectionState.remove(key);
-            } else {
-                return connectionState.put(key, value);
-            }
+            return key.convert(connectionState.remove(key));
         } else {
-            if (value == null) {
-                return sessionState.remove(key);
-            } else {
-                return sessionState.put(key, value);
-            }
+            return key.convert(sessionState.remove(key));
         }
     }
 
     @Override
-    public Object getAttachment(String key, State state) {
+    public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
         if (state == State.Connection) {
-            return connectionState.get(key);
+            return key.convert(connectionState.get(key));
         } else {
-            return sessionState.get(key);
+            return key.convert(sessionState.get(key));
         }
     }
 
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SMTPConstants.java b/protocols/api/src/test/java/org/apache/james/protocols/api/ProtocolSessionTest.java
similarity index 75%
copy from server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SMTPConstants.java
copy to protocols/api/src/test/java/org/apache/james/protocols/api/ProtocolSessionTest.java
index b401721..584735f 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SMTPConstants.java
+++ b/protocols/api/src/test/java/org/apache/james/protocols/api/ProtocolSessionTest.java
@@ -7,7 +7,7 @@
  * "License"); you may not use this file except in compliance   *
  * with the License.  You may obtain a copy of the License at   *
  *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ * http://www.apache.org/licenses/LICENSE-2.0                   *
  *                                                              *
  * Unless required by applicable law or agreed to in writing,   *
  * software distributed under the License is distributed on an  *
@@ -15,16 +15,18 @@
  * KIND, either express or implied.  See the License for the    *
  * specific language governing permissions and limitations      *
  * under the License.                                           *
- ****************************************************************/
+ ***************************************************************/
 
-package org.apache.james.smtpserver;
+package org.apache.james.protocols.api;
 
-/**
- * Constants which are used within SMTP Session
- */
-public interface SMTPConstants {
+import org.junit.jupiter.api.Test;
 
-    String DATA_MIMEMESSAGE_STREAMSOURCE = "org.apache.james.core.DataCmdHandler.DATA_MIMEMESSAGE_STREAMSOURCE";
-    String MAIL = "MAIL";
+import nl.jqno.equalsverifier.EqualsVerifier;
 
-}
+class ProtocolSessionTest {
+
+    @Test
+    void attachmentKeyShouldRespectBeanContract() {
+        EqualsVerifier.forClass(ProtocolSession.AttachmentKey.class).verify();
+    }
+}
\ No newline at end of file
diff --git a/protocols/lmtp/src/main/java/org/apache/james/protocols/lmtp/core/DataLineMessageHookHandler.java b/protocols/lmtp/src/main/java/org/apache/james/protocols/lmtp/core/DataLineMessageHookHandler.java
index 1e971cf..cc69dab 100644
--- a/protocols/lmtp/src/main/java/org/apache/james/protocols/lmtp/core/DataLineMessageHookHandler.java
+++ b/protocols/lmtp/src/main/java/org/apache/james/protocols/lmtp/core/DataLineMessageHookHandler.java
@@ -27,7 +27,7 @@ import org.apache.james.protocols.api.Response;
 import org.apache.james.protocols.api.handler.WiringException;
 import org.apache.james.protocols.lmtp.LMTPMultiResponse;
 import org.apache.james.protocols.lmtp.hook.DeliverToRecipientHook;
-import org.apache.james.protocols.smtp.MailEnvelopeImpl;
+import org.apache.james.protocols.smtp.MailEnvelope;
 import org.apache.james.protocols.smtp.SMTPResponse;
 import org.apache.james.protocols.smtp.SMTPRetCode;
 import org.apache.james.protocols.smtp.SMTPSession;
@@ -43,7 +43,7 @@ public class DataLineMessageHookHandler extends org.apache.james.protocols.smtp.
 
     
     @Override
-    protected Response processExtensions(SMTPSession session, MailEnvelopeImpl mail) {
+    protected Response processExtensions(SMTPSession session, MailEnvelope mail) {
         LMTPMultiResponse mResponse = null;
 
         for (MailAddress recipient : mail.getRecipients()) {
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/POP3Session.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/POP3Session.java
index 332cef4..1be4efd 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/POP3Session.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/POP3Session.java
@@ -19,8 +19,11 @@
 
 package org.apache.james.protocols.pop3;
 
+import java.util.List;
+
 import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.pop3.mailbox.Mailbox;
+import org.apache.james.protocols.pop3.mailbox.MessageMetaData;
 
 /**
  * All the handlers access this interface to communicate with POP3Handler object
@@ -28,9 +31,11 @@ import org.apache.james.protocols.pop3.mailbox.Mailbox;
 
 public interface POP3Session extends ProtocolSession {
 
-    String UID_LIST = "UID_LIST";
-    String DELETED_UID_LIST = "DELETED_UID_LIST";
-    String APOP_TIMESTAMP = "APOP_TIMESTAMP";
+    @SuppressWarnings("unchecked")
+    AttachmentKey<List<MessageMetaData>> UID_LIST = AttachmentKey.of("UID_LIST", (Class<List<MessageMetaData>>) (Object) List.class);
+    @SuppressWarnings("unchecked")
+    AttachmentKey<List<String>> DELETED_UID_LIST = AttachmentKey.of("DELETED_UID_LIST", (Class<List<String>>) (Object) List.class);
+    AttachmentKey<String> APOP_TIMESTAMP = AttachmentKey.of("APOP_TIMESTAMP", String.class);
 
     // Authentication states for the POP3 interaction
     /** Waiting for user id */
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractApopCmdHandler.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractApopCmdHandler.java
index 656339a..521c1df 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractApopCmdHandler.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/AbstractApopCmdHandler.java
@@ -37,10 +37,11 @@ import com.google.common.collect.ImmutableSet;
 public abstract class AbstractApopCmdHandler extends AbstractPassCmdHandler {
 
     private static final Collection<String> COMMANDS = ImmutableSet.of("APOP");
-    
+    private static final String MISSING_APOP_TIMESTAMP = "";
+
     @Override
     public Response onCommand(POP3Session session, Request request) {
-        if (session.getAttachment(POP3Session.APOP_TIMESTAMP, State.Connection) == null) {
+        if (!session.getAttachment(POP3Session.APOP_TIMESTAMP, State.Connection).isPresent()) {
             // APOP timestamp was not found in the session so APOP is not supported
             return POP3Response.ERR;
         }
@@ -81,7 +82,7 @@ public abstract class AbstractApopCmdHandler extends AbstractPassCmdHandler {
     
     @Override
     protected final Mailbox auth(POP3Session session, Username username, String password) throws Exception {
-        return auth(session, (String)session.getAttachment(POP3Session.APOP_TIMESTAMP, State.Connection), username, password);
+        return auth(session, session.getAttachment(POP3Session.APOP_TIMESTAMP, State.Connection).orElse(MISSING_APOP_TIMESTAMP), username, password);
     }
 
 
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/DeleCmdHandler.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/DeleCmdHandler.java
index 93263aa..ce499d7 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/DeleCmdHandler.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/DeleCmdHandler.java
@@ -19,6 +19,7 @@
 
 package org.apache.james.protocols.pop3.core;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
@@ -61,7 +62,12 @@ public class DeleCmdHandler implements CommandHandler<POP3Session> {
                     StringBuilder responseBuffer = new StringBuilder(64).append("Message (").append(num).append(") does not exist.");
                     return  new POP3Response(POP3Response.ERR_RESPONSE, responseBuffer.toString());
                 }
-                List<String> deletedUidList = (List<String>) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction);
+                List<String> deletedUidList = session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction)
+                    .orElseGet(() -> {
+                        ArrayList<String> uidList = new ArrayList<>();
+                        session.setAttachment(POP3Session.DELETED_UID_LIST, uidList, State.Transaction);
+                        return uidList;
+                    });
 
                 String uid = meta.getUid();
 
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/ListCmdHandler.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/ListCmdHandler.java
index 7cfeaf9..b706146 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/ListCmdHandler.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/ListCmdHandler.java
@@ -31,6 +31,7 @@ import org.apache.james.protocols.pop3.POP3Response;
 import org.apache.james.protocols.pop3.POP3Session;
 import org.apache.james.protocols.pop3.mailbox.MessageMetaData;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -55,8 +56,8 @@ public class ListCmdHandler implements CommandHandler<POP3Session> {
     @SuppressWarnings("unchecked")
     public Response onCommand(POP3Session session, Request request) {
         String parameters = request.getArgument();
-        List<MessageMetaData> uidList = (List<MessageMetaData>) session.getAttachment(POP3Session.UID_LIST, State.Transaction);
-        List<String> deletedUidList = (List<String>) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction);
+        List<MessageMetaData> uidList = session.getAttachment(POP3Session.UID_LIST, State.Transaction).orElse(ImmutableList.of());
+        List<String> deletedUidList = session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction).orElse(ImmutableList.of());
 
         if (session.getHandlerState() == POP3Session.TRANSACTION) {
             POP3Response response = null;
@@ -66,10 +67,10 @@ public class ListCmdHandler implements CommandHandler<POP3Session> {
                 long size = 0;
                 int count = 0;
                 List<MessageMetaData> validResults = new ArrayList<>();
-                if (uidList.isEmpty() == false) {
+                if (!uidList.isEmpty()) {
 
                     for (MessageMetaData data : uidList) {
-                        if (deletedUidList.contains(data.getUid()) == false) {
+                        if (!deletedUidList.contains(data.getUid())) {
                             size += data.getSize();
                             count++;
                             validResults.add(data);
@@ -95,7 +96,7 @@ public class ListCmdHandler implements CommandHandler<POP3Session> {
                         return  new POP3Response(POP3Response.ERR_RESPONSE, responseBuffer.toString());
                     }
                     
-                    if (deletedUidList.contains(data.getUid()) == false) {
+                    if (!deletedUidList.contains(data.getUid())) {
                         StringBuilder responseBuffer = new StringBuilder(64).append(num).append(" ").append(data.getSize());
                         response = new POP3Response(POP3Response.OK_RESPONSE, responseBuffer.toString());
                     } else {
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/MessageMetaDataUtils.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/MessageMetaDataUtils.java
index 477f5cf..339c758 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/MessageMetaDataUtils.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/MessageMetaDataUtils.java
@@ -19,7 +19,6 @@
 
 package org.apache.james.protocols.pop3.core;
 
-import java.util.List;
 import java.util.stream.IntStream;
 
 import org.apache.james.protocols.api.ProtocolSession.State;
@@ -33,13 +32,10 @@ public class MessageMetaDataUtils {
      * found.
      */
     public static MessageMetaData getMetaData(POP3Session session, int number) {
-        @SuppressWarnings("unchecked")
-        List<MessageMetaData> uidList = (List<MessageMetaData>) session.getAttachment(POP3Session.UID_LIST, State.Transaction);
-        if (uidList == null || number > uidList.size()) {
-            return null;
-        } else {
-            return uidList.get(number - 1);
-        }
+        return session.getAttachment(POP3Session.UID_LIST, State.Transaction)
+            .filter(uidList -> number <= uidList.size())
+            .map(uidList -> uidList.get(number - 1))
+            .orElse(null);
     }
 
     /**
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/QuitCmdHandler.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/QuitCmdHandler.java
index 791c062..f61714d 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/QuitCmdHandler.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/QuitCmdHandler.java
@@ -33,6 +33,7 @@ import org.apache.james.protocols.pop3.mailbox.Mailbox;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -59,13 +60,12 @@ public class QuitCmdHandler implements CommandHandler<POP3Session> {
      * cleanup of the POP3Handler state.
      */
     @Override
-    @SuppressWarnings("unchecked")
     public Response onCommand(POP3Session session, Request request) {
         Response response = null;
         if (session.getHandlerState() == POP3Session.AUTHENTICATION_READY || session.getHandlerState() == POP3Session.AUTHENTICATION_USERSET) {
             return SIGN_OFF;
         }
-        List<String> toBeRemoved = (List<String>) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction);
+        List<String> toBeRemoved = session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction).orElse(ImmutableList.of());
         Mailbox mailbox = session.getUserMailbox();
         try {
             String[] uids = toBeRemoved.toArray(new String[toBeRemoved.size()]);
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/RetrCmdHandler.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/RetrCmdHandler.java
index f87d604..99d050c 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/RetrCmdHandler.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/RetrCmdHandler.java
@@ -34,6 +34,7 @@ import org.apache.james.protocols.pop3.POP3StreamResponse;
 import org.apache.james.protocols.pop3.mailbox.MessageMetaData;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -70,10 +71,10 @@ public class RetrCmdHandler implements CommandHandler<POP3Session> {
                     response = new POP3Response(POP3Response.ERR_RESPONSE, responseBuffer.toString());
                     return response;
                 }
-                List<String> deletedUidList = (List<String>) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction);
+                List<String> deletedUidList = session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction).orElse(ImmutableList.of());
 
                 String uid = data.getUid();
-                if (deletedUidList.contains(uid) == false) {
+                if (!deletedUidList.contains(uid)) {
                     InputStream content = session.getUserMailbox().getMessage(uid);
 
                     if (content != null) {
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/RsetCmdHandler.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/RsetCmdHandler.java
index 74601ad..f88ec0b 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/RsetCmdHandler.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/RsetCmdHandler.java
@@ -69,7 +69,7 @@ public class RsetCmdHandler implements CommandHandler<POP3Session> {
             List<MessageMetaData> messages = session.getUserMailbox().getMessages();
 
             session.setAttachment(POP3Session.UID_LIST, messages, State.Transaction);
-            session.setAttachment(POP3Session.DELETED_UID_LIST, new ArrayList<String>(), State.Transaction);
+            session.setAttachment(POP3Session.DELETED_UID_LIST, new ArrayList<>(), State.Transaction);
         } catch (IOException e) {
             // In the event of an exception being thrown there may or may not be
             // anything in userMailbox
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/StatCmdHandler.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/StatCmdHandler.java
index 89105f9..f942124 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/StatCmdHandler.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/StatCmdHandler.java
@@ -31,6 +31,7 @@ import org.apache.james.protocols.pop3.POP3Response;
 import org.apache.james.protocols.pop3.POP3Session;
 import org.apache.james.protocols.pop3.mailbox.MessageMetaData;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -44,18 +45,17 @@ public class StatCmdHandler implements CommandHandler<POP3Session> {
      * of messages in the mailbox and its aggregate size.
      */
     @Override
-    @SuppressWarnings("unchecked")
     public Response onCommand(POP3Session session, Request request) {
         if (session.getHandlerState() == POP3Session.TRANSACTION) {
 
-            List<MessageMetaData> uidList = (List<MessageMetaData>) session.getAttachment(POP3Session.UID_LIST, State.Transaction);
-            List<String> deletedUidList = (List<String>) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction);
+            List<MessageMetaData> uidList = session.getAttachment(POP3Session.UID_LIST, State.Transaction).orElse(ImmutableList.of());
+            List<String> deletedUidList = session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction).orElse(ImmutableList.of());
             long size = 0;
             int count = 0;
-            if (uidList.isEmpty() == false) {
+            if (!uidList.isEmpty()) {
                 List<MessageMetaData> validResults = new ArrayList<>();
                 for (MessageMetaData data : uidList) {
-                    if (deletedUidList.contains(data.getUid()) == false) {
+                    if (!deletedUidList.contains(data.getUid())) {
                         size += data.getSize();
                         count++;
                         validResults.add(data);
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java
index b77f3ff..5931a2b 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java
@@ -88,10 +88,10 @@ public class TopCmdHandler extends RetrCmdHandler implements CapaCapability {
                     return  new POP3Response(POP3Response.ERR_RESPONSE, responseBuffer.toString());
                 }
                 
-                List<String> deletedUidList = (List<String>) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction);
+                List<String> deletedUidList = session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction).orElse(ImmutableList.of());
 
                 String uid = data.getUid();
-                if (deletedUidList.contains(uid) == false) {
+                if (!deletedUidList.contains(uid)) {
 
                     InputStream message = new CountingBodyInputStream(new ExtraDotInputStream(new CRLFTerminatedInputStream(session.getUserMailbox().getMessage(uid))), lines);
                     return new POP3StreamResponse(POP3Response.OK_RESPONSE, "Message follows", message);
diff --git a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/UidlCmdHandler.java b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/UidlCmdHandler.java
index 7f33832..4155a65 100644
--- a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/UidlCmdHandler.java
+++ b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/UidlCmdHandler.java
@@ -33,6 +33,7 @@ import org.apache.james.protocols.pop3.POP3Response;
 import org.apache.james.protocols.pop3.POP3Session;
 import org.apache.james.protocols.pop3.mailbox.MessageMetaData;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
 /**
@@ -47,13 +48,12 @@ public class UidlCmdHandler implements CommandHandler<POP3Session>, CapaCapabili
      * of message ids to the client.
      */
     @Override
-    @SuppressWarnings("unchecked")
     public Response onCommand(POP3Session session, Request request) {
         POP3Response response = null;
         String parameters = request.getArgument();
         if (session.getHandlerState() == POP3Session.TRANSACTION) {
-            List<MessageMetaData> uidList = (List<MessageMetaData>) session.getAttachment(POP3Session.UID_LIST, State.Transaction);
-            List<String> deletedUidList = (List<String>) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction);
+            List<MessageMetaData> uidList = session.getAttachment(POP3Session.UID_LIST, State.Transaction).orElse(ImmutableList.of());
+            List<String> deletedUidList = session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction).orElse(ImmutableList.of());
             try {
                 String identifier = session.getUserMailbox().getIdentifier();
                 if (parameters == null) {
@@ -61,7 +61,7 @@ public class UidlCmdHandler implements CommandHandler<POP3Session>, CapaCapabili
 
                     for (int i = 0; i < uidList.size(); i++) {
                         MessageMetaData metadata = uidList.get(i);
-                        if (deletedUidList.contains(metadata.getUid()) == false) {
+                        if (!deletedUidList.contains(metadata.getUid())) {
                             StringBuilder responseBuffer = new StringBuilder().append(i + 1).append(" ").append(metadata.getUid(identifier));
                             response.appendLine(responseBuffer.toString());
                         }
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPSession.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPSession.java
index 02c84c2..1167750 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPSession.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPSession.java
@@ -19,6 +19,10 @@
 
 package org.apache.james.protocols.smtp;
 
+import java.util.List;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.core.MaybeSender;
 import org.apache.james.protocols.api.ProtocolSession;
 
 /**
@@ -30,12 +34,13 @@ public interface SMTPSession extends ProtocolSession {
 
     // Keys used to store/lookup data in the internal state hash map
     /** Sender's email address */
-    String SENDER = "SENDER_ADDRESS";
+    AttachmentKey<MaybeSender> SENDER = AttachmentKey.of("SENDER_ADDRESS", MaybeSender.class);
     /** The message recipients */
-    String RCPT_LIST = "RCPT_LIST";
+    @SuppressWarnings("unchecked")
+    AttachmentKey<List<MailAddress>> RCPT_LIST = AttachmentKey.of("RCPT_LIST", (Class<List<MailAddress>>) (Object) List.class);
     /** HELO or EHLO */
-    String CURRENT_HELO_MODE = "CURRENT_HELO_MODE";
-    String CURRENT_HELO_NAME = "CURRENT_HELO_NAME";
+    AttachmentKey<String> CURRENT_HELO_MODE = AttachmentKey.of("CURRENT_HELO_MODE", String.class);
+    AttachmentKey<String> CURRENT_HELO_NAME = AttachmentKey.of("CURRENT_HELO_NAME", String.class);
 
     /**
      * Returns the service wide configuration
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPSessionImpl.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPSessionImpl.java
index 91cde64..6b02cf4 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPSessionImpl.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPSessionImpl.java
@@ -18,9 +18,9 @@
  ****************************************************************/
 package org.apache.james.protocols.smtp;
 
-import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
 
-import org.apache.james.core.MailAddress;
 import org.apache.james.protocols.api.ProtocolSessionImpl;
 import org.apache.james.protocols.api.ProtocolTransport;
 import org.apache.james.protocols.api.Response;
@@ -65,27 +65,19 @@ public class SMTPSessionImpl extends ProtocolSessionImpl implements SMTPSession
     @Override
     public void resetState() {
         // remember the ehlo mode between resets
-        Object currentHeloMode = getState().get(CURRENT_HELO_MODE);
+        Optional<String> currentHeloMode = getAttachment(CURRENT_HELO_MODE, State.Transaction);
 
         getState().clear();
 
         // start again with the old helo mode
-        if (currentHeloMode != null) {
-            getState().put(CURRENT_HELO_MODE, currentHeloMode);
-        }
+        currentHeloMode.ifPresent(heloMode -> setAttachment(CURRENT_HELO_MODE, heloMode, State.Transaction));
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public int getRcptCount() {
-        int count = 0;
-
-        // check if the key exists
-        if (getState().get(SMTPSession.RCPT_LIST) != null) {
-            count = ((Collection<MailAddress>) getState().get(SMTPSession.RCPT_LIST)).size();
-        }
-
-        return count;
+        return getAttachment(SMTPSession.RCPT_LIST, State.Transaction)
+            .map(List::size)
+            .orElse(0);
     }
 
     @Override
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractAddHeadersFilter.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractAddHeadersFilter.java
index 9c29ffd..8f0e8e3 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractAddHeadersFilter.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractAddHeadersFilter.java
@@ -25,6 +25,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.api.Response;
 import org.apache.james.protocols.api.handler.LineHandler;
@@ -39,8 +40,8 @@ public abstract class AbstractAddHeadersFilter extends SeparatingDataLineFilter
 
     private static final AtomicInteger COUNTER = new AtomicInteger(0);
     
-    private final String headersPrefixAdded = "HEADERS_PREFIX_ADDED" + COUNTER.incrementAndGet();
-    private final String headersSuffixAdded = "HEADERS_SUFFIX_ADDED" + COUNTER.incrementAndGet();
+    private final ProtocolSession.AttachmentKey<Boolean> headersPrefixAdded = ProtocolSession.AttachmentKey.of("HEADERS_PREFIX_ADDED" + COUNTER.incrementAndGet(), Boolean.class);
+    private final ProtocolSession.AttachmentKey<Boolean> headersSuffixAdded = ProtocolSession.AttachmentKey.of("HEADERS_SUFFIX_ADDED" + COUNTER.incrementAndGet(), Boolean.class);
 
     enum Location {
         Prefix,
@@ -57,7 +58,7 @@ public abstract class AbstractAddHeadersFilter extends SeparatingDataLineFilter
     
     @Override
     protected Response onSeparatorLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
-        if (getLocation() == Location.Suffix && session.getAttachment(headersSuffixAdded, State.Transaction) == null) { 
+        if (getLocation() == Location.Suffix && !session.getAttachment(headersSuffixAdded, State.Transaction).isPresent()) {
             session.setAttachment(headersSuffixAdded, Boolean.TRUE, State.Transaction);
             return addHeaders(session, line, next);
         }
@@ -66,7 +67,7 @@ public abstract class AbstractAddHeadersFilter extends SeparatingDataLineFilter
 
     @Override
     protected Response onHeadersLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
-        if (getLocation() == Location.Prefix && session.getAttachment(headersPrefixAdded, State.Transaction) == null) {
+        if (getLocation() == Location.Prefix && !session.getAttachment(headersPrefixAdded, State.Transaction).isPresent()) {
             session.setAttachment(headersPrefixAdded, Boolean.TRUE, State.Transaction);
             return addHeaders(session, line, next);
         }
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractSenderAuthIdentifyVerificationRcptHook.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractSenderAuthIdentifyVerificationRcptHook.java
index 487ec8c..e709b3e 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractSenderAuthIdentifyVerificationRcptHook.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractSenderAuthIdentifyVerificationRcptHook.java
@@ -46,7 +46,7 @@ public abstract class AbstractSenderAuthIdentifyVerificationRcptHook implements
     @Override
     public HookResult doRcpt(SMTPSession session, MaybeSender sender, MailAddress rcpt) {
         if (session.getUsername() != null) {
-            MaybeSender senderAddress = (MaybeSender) session.getAttachment(SMTPSession.SENDER, ProtocolSession.State.Transaction);
+            MaybeSender senderAddress = session.getAttachment(SMTPSession.SENDER, ProtocolSession.State.Transaction).orElse(MaybeSender.nullSender());
             
             // Check if the sender address is the same as the user which was used to authenticate.
             // Its important to ignore case here to fix JAMES-837. This is save todo because if the handler is called
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/DataCmdHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/DataCmdHandler.java
index 8bebea0..d93b22f 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/DataCmdHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/DataCmdHandler.java
@@ -21,7 +21,6 @@ package org.apache.james.protocols.smtp.core;
 import java.io.Closeable;
 import java.io.IOException;
 import java.nio.ByteBuffer;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
@@ -49,6 +48,7 @@ import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.dsn.DSNStatus;
 import org.apache.james.util.MDCBuilder;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 
 
@@ -112,7 +112,7 @@ public class DataCmdHandler implements CommandHandler<SMTPSession>, ExtensibleHa
         }
     }
    
-    public static final String MAILENV = "MAILENV";
+    public static final ProtocolSession.AttachmentKey<MailEnvelope> MAILENV = ProtocolSession.AttachmentKey.of("MAILENV", MailEnvelope.class);
 
     private final MetricFactory metricFactory;
 
@@ -161,9 +161,9 @@ public class DataCmdHandler implements CommandHandler<SMTPSession>, ExtensibleHa
      */
     @SuppressWarnings("unchecked")
     protected Response doDATA(SMTPSession session, String argument) {
-        MaybeSender sender = (MaybeSender) session.getAttachment(SMTPSession.SENDER, ProtocolSession.State.Transaction);
-        MailEnvelope env = createEnvelope(session, sender, new ArrayList<>((Collection<MailAddress>) session.getAttachment(SMTPSession.RCPT_LIST, ProtocolSession.State.Transaction)));
-        session.setAttachment(MAILENV, env,ProtocolSession.State.Transaction);
+        MaybeSender sender = session.getAttachment(SMTPSession.SENDER, ProtocolSession.State.Transaction).orElse(MaybeSender.nullSender());
+        MailEnvelope env = createEnvelope(session, sender, session.getAttachment(SMTPSession.RCPT_LIST, ProtocolSession.State.Transaction).orElse(ImmutableList.of()));
+        session.setAttachment(MAILENV, env, ProtocolSession.State.Transaction);
         session.pushLineHandler(lineHandler);
         
         return DATA_READY;
@@ -208,9 +208,9 @@ public class DataCmdHandler implements CommandHandler<SMTPSession>, ExtensibleHa
         if ((argument != null) && (argument.length() > 0)) {
             return UNEXPECTED_ARG;
         }
-        if (session.getAttachment(SMTPSession.SENDER, ProtocolSession.State.Transaction) == null) {
+        if (!session.getAttachment(SMTPSession.SENDER, ProtocolSession.State.Transaction).isPresent()) {
             return NO_SENDER;
-        } else if (session.getAttachment(SMTPSession.RCPT_LIST, ProtocolSession.State.Transaction) == null) {
+        } else if (!session.getAttachment(SMTPSession.RCPT_LIST, ProtocolSession.State.Transaction).isPresent()) {
             return NO_RECIPIENT;
         }
         return null;
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/DataLineMessageHookHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/DataLineMessageHookHandler.java
index cc645ea..80aded3 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/DataLineMessageHookHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/DataLineMessageHookHandler.java
@@ -32,7 +32,7 @@ import org.apache.james.protocols.api.Response;
 import org.apache.james.protocols.api.handler.ExtensibleHandler;
 import org.apache.james.protocols.api.handler.LineHandler;
 import org.apache.james.protocols.api.handler.WiringException;
-import org.apache.james.protocols.smtp.MailEnvelopeImpl;
+import org.apache.james.protocols.smtp.MailEnvelope;
 import org.apache.james.protocols.smtp.SMTPResponse;
 import org.apache.james.protocols.smtp.SMTPRetCode;
 import org.apache.james.protocols.smtp.SMTPSession;
@@ -59,8 +59,10 @@ public class DataLineMessageHookHandler implements DataLineFilter, ExtensibleHan
 
     @Override
     public Response onLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
-        MailEnvelopeImpl env = (MailEnvelopeImpl) session.getAttachment(DataCmdHandler.MAILENV, ProtocolSession.State.Transaction);
-        OutputStream out = env.getMessageOutputStream();
+        MailEnvelope env = session.getAttachment(DataCmdHandler.MAILENV, ProtocolSession.State.Transaction)
+            .orElseThrow(() -> new RuntimeException("'" + DataCmdHandler.MAILENV.asString() + "' has not been filled."));
+
+        OutputStream out = getMessageOutputStream(env);
         try {
             // 46 is "."
             // Stream terminated            
@@ -95,6 +97,14 @@ public class DataLineMessageHookHandler implements DataLineFilter, ExtensibleHan
         return null;
     }
 
+    private OutputStream getMessageOutputStream(MailEnvelope env) {
+        try {
+            return env.getMessageOutputStream();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     private byte[] readBytes(ByteBuffer line) {
         line.rewind();
         byte[] bline;
@@ -107,10 +117,10 @@ public class DataLineMessageHookHandler implements DataLineFilter, ExtensibleHan
         return bline;
     }
 
-    protected Response processExtensions(SMTPSession session, MailEnvelopeImpl mail) {
+    protected Response processExtensions(SMTPSession session, MailEnvelope mail) {
        
 
-        if (mail != null && messageHandlers != null) {
+        if (messageHandlers != null) {
             for (Object messageHandler : messageHandlers) {
                 MessageHook rawHandler = (MessageHook) messageHandler;
                 LOGGER.debug("executing message handler {}", rawHandler);
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/MailCmdHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/MailCmdHandler.java
index a9853e4..5f837e7 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/MailCmdHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/MailCmdHandler.java
@@ -87,7 +87,7 @@ public class MailCmdHandler extends AbstractHookableCmdHandler<MailHook> {
         // Check if the response was not ok
         if (response.getRetCode().equals(SMTPRetCode.MAIL_OK) == false) {
             // cleanup the session
-            session.setAttachment(SMTPSession.SENDER, null,  State.Transaction);
+            session.removeAttachment(SMTPSession.SENDER, State.Transaction);
         }
 
         return response;
@@ -99,16 +99,14 @@ public class MailCmdHandler extends AbstractHookableCmdHandler<MailHook> {
      * 
      * @param session
      *            SMTP session object
-     * @param argument
-     *            the argument passed in with the command by the SMTP client
      */
-    private Response doMAIL(SMTPSession session, String argument) {
+    private Response doMAIL(SMTPSession session) {
         StringBuilder responseBuffer = new StringBuilder();
-        MaybeSender sender = (MaybeSender) session.getAttachment(SMTPSession.SENDER, State.Transaction);
+        MaybeSender sender = session.getAttachment(SMTPSession.SENDER, State.Transaction).orElse(MaybeSender.nullSender());
         responseBuffer.append(
                 DSNStatus.getStatus(DSNStatus.SUCCESS, DSNStatus.ADDRESS_OTHER))
                 .append(" Sender <");
-        if (sender != null) {
+        if (!sender.isNullSender()) {
             responseBuffer.append(sender.asString());
         }
         responseBuffer.append("> OK");
@@ -123,7 +121,7 @@ public class MailCmdHandler extends AbstractHookableCmdHandler<MailHook> {
     @Override
     protected Response doCoreCmd(SMTPSession session, String command,
                                  String parameters) {
-        return doMAIL(session, parameters);
+        return doMAIL(session);
     }
 
     @Override
@@ -146,10 +144,10 @@ public class MailCmdHandler extends AbstractHookableCmdHandler<MailHook> {
             sender = argument.substring(colonIndex + 1);
             argument = argument.substring(0, colonIndex);
         }
-        if (session.getAttachment(SMTPSession.SENDER, State.Transaction) != null) {
+        if (session.getAttachment(SMTPSession.SENDER, State.Transaction).isPresent()) {
             return SENDER_ALREADY_SPECIFIED;
-        } else if (session.getAttachment(
-                SMTPSession.CURRENT_HELO_MODE, State.Connection) == null
+        } else if (!session.getAttachment(
+                SMTPSession.CURRENT_HELO_MODE, State.Connection).isPresent()
                 && session.getConfiguration().useHeloEhloEnforcement()) {
             return EHLO_HELO_NEEDED;
         } else if (argument == null
@@ -248,7 +246,7 @@ public class MailCmdHandler extends AbstractHookableCmdHandler<MailHook> {
 
     @Override
     protected HookResult callHook(MailHook rawHook, SMTPSession session, String parameters) {
-        MaybeSender sender = (MaybeSender) session.getAttachment(SMTPSession.SENDER, State.Transaction);
+        MaybeSender sender = session.getAttachment(SMTPSession.SENDER, State.Transaction).orElse(MaybeSender.nullSender());
         return rawHook.doMail(session, sender);
     }
     
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java
index c5e8815..93ce9d6 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/RcptCmdHandler.java
@@ -21,6 +21,7 @@ package org.apache.james.protocols.smtp.core;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.List;
 import java.util.Locale;
 import java.util.StringTokenizer;
 
@@ -29,6 +30,7 @@ import javax.inject.Inject;
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
 import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.api.Response;
 import org.apache.james.protocols.api.handler.CommandHandler;
@@ -49,7 +51,7 @@ import com.google.common.collect.ImmutableSet;
 public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> implements
         CommandHandler<SMTPSession> {
     private static final Logger LOGGER = LoggerFactory.getLogger(RcptCmdHandler.class);
-    public static final String CURRENT_RECIPIENT = "CURRENT_RECIPIENT"; 
+    public static final ProtocolSession.AttachmentKey<MailAddress> CURRENT_RECIPIENT = ProtocolSession.AttachmentKey.of("CURRENT_RECIPIENT", MailAddress.class);
     private static final Collection<String> COMMANDS = ImmutableSet.of("RCPT");
     private static final Response MAIL_NEEDED = new SMTPResponse(SMTPRetCode.BAD_SEQUENCE, DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_OTHER) + " Need MAIL before RCPT").immutable();
     private static final Response SYNTAX_ERROR_ARGS = new SMTPResponse(SMTPRetCode.SYNTAX_ERROR_ARGUMENTS, DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_SYNTAX) + " Usage: RCPT TO:<recipient>").immutable();
@@ -74,16 +76,9 @@ public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> impleme
      *            parameters passed in with the command by the SMTP client
      */
     @Override
-    @SuppressWarnings("unchecked")
-    protected Response doCoreCmd(SMTPSession session, String command,
-            String parameters) {
-        Collection<MailAddress> rcptColl = (Collection<MailAddress>) session.getAttachment(
-                SMTPSession.RCPT_LIST, State.Transaction);
-        if (rcptColl == null) {
-            rcptColl = new ArrayList<>();
-        }
-        MailAddress recipientAddress = (MailAddress) session.getAttachment(
-                CURRENT_RECIPIENT, State.Transaction);
+    protected Response doCoreCmd(SMTPSession session, String command, String parameters) {
+        List<MailAddress> rcptColl = session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction).orElseGet(ArrayList::new);
+        MailAddress recipientAddress = session.getAttachment(CURRENT_RECIPIENT, State.Transaction).orElse(MailAddress.nullSender());
         rcptColl.add(recipientAddress);
         session.setAttachment(SMTPSession.RCPT_LIST, rcptColl, State.Transaction);
         StringBuilder response = new StringBuilder();
@@ -111,7 +106,7 @@ public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> impleme
             recipient = argument.substring(colonIndex + 1);
             argument = argument.substring(0, colonIndex);
         }
-        if (session.getAttachment(SMTPSession.SENDER, State.Transaction) == null) {
+        if (!session.getAttachment(SMTPSession.SENDER, State.Transaction).isPresent()) {
             return MAIL_NEEDED;
         } else if (argument == null
                 || !argument.toUpperCase(Locale.US).equals("TO")
@@ -187,7 +182,7 @@ public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> impleme
             optionTokenizer = null;
         }
 
-        session.setAttachment(CURRENT_RECIPIENT,recipientAddress, State.Transaction);
+        session.setAttachment(CURRENT_RECIPIENT, recipientAddress, State.Transaction);
 
         return null;
     }
@@ -199,8 +194,9 @@ public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> impleme
         } else if (null != recipient) {
             sb.append(" [to:").append(recipient).append(']');
         }
-       MaybeSender sender = (MaybeSender) session.getAttachment(SMTPSession.SENDER, State.Transaction);
-        if (null != sender && !sender.isNullSender()) {
+
+        MaybeSender sender = session.getAttachment(SMTPSession.SENDER, State.Transaction).orElse(MaybeSender.nullSender());
+        if (!sender.isNullSender()) {
             sb.append(" [from:").append(sender.asString()).append(']');
         }
         return sb.toString();
@@ -218,9 +214,8 @@ public class RcptCmdHandler extends AbstractHookableCmdHandler<RcptHook> impleme
 
     @Override
     protected HookResult callHook(RcptHook rawHook, SMTPSession session, String parameters) {
-        MaybeSender sender = (MaybeSender) session.getAttachment(SMTPSession.SENDER, State.Transaction);
-        return rawHook.doRcpt(session, sender,
-                (MailAddress) session.getAttachment(CURRENT_RECIPIENT, State.Transaction));
+        MaybeSender sender = session.getAttachment(SMTPSession.SENDER, State.Transaction).orElse(MaybeSender.nullSender());
+        return rawHook.doRcpt(session, sender, session.getAttachment(CURRENT_RECIPIENT, State.Transaction).orElse(MailAddress.nullSender()));
     }
 
     protected String getDefaultDomain() {
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java
index 48b0a73..3c24277 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/ReceivedDataLineFilter.java
@@ -25,11 +25,14 @@ import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
+import java.util.Optional;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.smtp.SMTPSession;
 
+import com.google.common.collect.ImmutableList;
+
 /**
  * {@link AbstractAddHeadersFilter} which adds the Received header for the message.
  */
@@ -85,30 +88,31 @@ public class ReceivedDataLineFilter extends AbstractAddHeadersFilter {
 
         StringBuilder headerLineBuffer = new StringBuilder();
 
-        String heloMode = (String) session.getAttachment(SMTPSession.CURRENT_HELO_MODE, State.Connection);
-        String heloName = (String) session.getAttachment(SMTPSession.CURRENT_HELO_NAME, State.Connection);
+        Optional<String> heloMode = session.getAttachment(SMTPSession.CURRENT_HELO_MODE, State.Connection);
+        Optional<String> heloName = session.getAttachment(SMTPSession.CURRENT_HELO_NAME, State.Connection);
 
         // Put our Received header first
         headerLineBuffer.append("from ").append(session.getRemoteAddress().getHostName());
 
-        if (heloName != null) {
-            headerLineBuffer.append(" (").append(heloMode).append(" ").append(heloName).append(")");
+        if (heloName.isPresent() && heloMode.isPresent()) {
+            headerLineBuffer.append(" (").append(heloMode.get()).append(" ").append(heloName.get()).append(")");
         }
         headerLineBuffer.append(" ([").append(session.getRemoteAddress().getAddress().getHostAddress()).append("])");
         Header header = new Header("Received", headerLineBuffer.toString());
         
         headerLineBuffer = new StringBuilder();
-        headerLineBuffer.append("by ").append(session.getConfiguration().getHelloName()).append(" (").append(session.getConfiguration().getSoftwareName()).append(") with ").append(getServiceType(session, heloMode));
+        headerLineBuffer.append("by ").append(session.getConfiguration().getHelloName()).append(" (").append(session.getConfiguration().getSoftwareName()).append(") with ").append(getServiceType(session, heloMode.orElse("NOT-DEFINED")));
         headerLineBuffer.append(" ID ").append(session.getSessionID());
 
-        if (((Collection<?>) session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction)).size() == 1) {
+        List<MailAddress> rcptList = session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction).orElse(ImmutableList.of());
+        if (rcptList.size() == 1) {
             // Only indicate a recipient if they're the only recipient
             // (prevents email address harvesting and large headers in
             // bulk email)
             header.add(headerLineBuffer.toString());
             
             headerLineBuffer = new StringBuilder();
-            headerLineBuffer.append("for <").append(((List<MailAddress>) session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction)).get(0).toString()).append(">;");
+            headerLineBuffer.append("for <").append(rcptList.get(0).toString()).append(">;");
         } else {
             // Put the ; on the end of the 'by' line
             headerLineBuffer.append(";");
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/SeparatingDataLineFilter.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/SeparatingDataLineFilter.java
index 4e03460..2b18f3a 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/SeparatingDataLineFilter.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/SeparatingDataLineFilter.java
@@ -20,6 +20,7 @@ package org.apache.james.protocols.smtp.core;
 
 import java.nio.ByteBuffer;
 
+import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.api.Response;
 import org.apache.james.protocols.api.handler.LineHandler;
@@ -46,11 +47,11 @@ import org.apache.james.protocols.smtp.SMTPSession;
  */
 public abstract class SeparatingDataLineFilter implements DataLineFilter {
 
-    private static final String HEADERS_COMPLETE = "HEADERS_COMPLETE";
+    private static final ProtocolSession.AttachmentKey<Boolean> HEADERS_COMPLETE = ProtocolSession.AttachmentKey.of("HEADERS_COMPLETE", Boolean.class);
     
     @Override
     public final Response onLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
-        if (session.getAttachment(HEADERS_COMPLETE, State.Transaction) == null) {
+        if (!session.getAttachment(HEADERS_COMPLETE, State.Transaction).isPresent()) {
             if (line.remaining() == 2) {
                 if (line.get() == '\r' && line.get() == '\n') {
                     line.rewind();
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/UnknownCmdHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/UnknownCmdHandler.java
index bc0c414..f50e03b 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/UnknownCmdHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/UnknownCmdHandler.java
@@ -26,6 +26,7 @@ import java.util.Collection;
 import javax.inject.Inject;
 
 import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.api.Response;
 import org.apache.james.protocols.api.handler.UnknownCommandHandler;
@@ -47,6 +48,8 @@ public class UnknownCmdHandler extends AbstractHookableCmdHandler<UnknownHook> {
      * The name of the command handled by the command handler
      */
     private static final Collection<String> COMMANDS = ImmutableSet.of(UnknownCommandHandler.COMMAND_IDENTIFIER);
+    private static final String MISSING_CURR_COMMAND = "";
+    public static final ProtocolSession.AttachmentKey<String> CURR_COMMAND = ProtocolSession.AttachmentKey.of("CURR_COMMAND", String.class);
 
     @Inject
     public UnknownCmdHandler(MetricFactory metricFactory) {
@@ -67,13 +70,13 @@ public class UnknownCmdHandler extends AbstractHookableCmdHandler<UnknownHook> {
 
     @Override
     protected Response doFilterChecks(SMTPSession session, String command, String parameters) {
-        session.setAttachment("CURR_COMMAND", command, State.Transaction);
+        session.setAttachment(CURR_COMMAND, command, State.Transaction);
         return null;
     }
 
     @Override
     protected HookResult callHook(UnknownHook rawHook, SMTPSession session, String parameters) {
-        return rawHook.doUnknown(session, (String) session.getAttachment("CURR_COMMAND", State.Transaction));
+        return rawHook.doUnknown(session, session.getAttachment(CURR_COMMAND, State.Transaction).orElse(MISSING_CURR_COMMAND));
     }
 
     @Override
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/MailSizeEsmtpExtension.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/MailSizeEsmtpExtension.java
index e951d71..16a54e9 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/MailSizeEsmtpExtension.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/MailSizeEsmtpExtension.java
@@ -23,8 +23,10 @@ import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 import org.apache.james.core.MaybeSender;
+import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.api.Response;
 import org.apache.james.protocols.api.handler.LineHandler;
@@ -48,8 +50,9 @@ public class MailSizeEsmtpExtension implements MailParametersHook, EhloExtension
 
     private static final Logger LOGGER = LoggerFactory.getLogger(MailSizeEsmtpExtension.class);
 
-    private static final String MESG_SIZE = "MESG_SIZE"; // The size of the
-    private static final String MESG_FAILED = "MESG_FAILED";   // Message failed flag
+    private static final ProtocolSession.AttachmentKey<Integer> MESG_SIZE = ProtocolSession.AttachmentKey.of("MESG_SIZE", Integer.class); // The size of the
+    private static final ProtocolSession.AttachmentKey<Boolean> MESG_FAILED = ProtocolSession.AttachmentKey.of("MESG_FAILED", Boolean.class);   // Message failed flag
+    public static final ProtocolSession.AttachmentKey<Long> CURRENT_SIZE = ProtocolSession.AttachmentKey.of("CURRENT_SIZE", Long.class);
     private static final String[] MAIL_PARAMS = { "SIZE" };
     
     private static final HookResult SYNTAX_ERROR = HookResult.builder()
@@ -68,7 +71,7 @@ public class MailSizeEsmtpExtension implements MailParametersHook, EhloExtension
     @Override
     public HookResult doMailParameter(SMTPSession session, String paramName,
                                       String paramValue) {
-        MaybeSender tempSender = (MaybeSender) session.getAttachment(SMTPSession.SENDER, State.Transaction);
+        MaybeSender tempSender = session.getAttachment(SMTPSession.SENDER, State.Transaction).orElse(MaybeSender.nullSender());
         return doMailSize(session, paramValue, tempSender);
     }
 
@@ -134,10 +137,10 @@ public class MailSizeEsmtpExtension implements MailParametersHook, EhloExtension
 
     @Override
     public Response onLine(SMTPSession session, ByteBuffer line, LineHandler<SMTPSession> next) {
-        Boolean failed = (Boolean) session.getAttachment(MESG_FAILED, State.Transaction);
+        Optional<Boolean> failed = session.getAttachment(MESG_FAILED, State.Transaction);
         // If we already defined we failed and sent a reply we should simply
         // wait for a CRLF.CRLF to be sent by the client.
-        if (failed != null && failed) {
+        if (failed.isPresent() && failed.get()) {
             if (isDataTerminated(line)) {
                 line.rewind();
                 next.onLine(session, line);
@@ -151,15 +154,11 @@ public class MailSizeEsmtpExtension implements MailParametersHook, EhloExtension
                 return next.onLine(session, line);
             } else {
                 line.rewind();
-                Long currentSize = (Long) session.getAttachment("CURRENT_SIZE", State.Transaction);
-                Long newSize;
-                if (currentSize == null) {
-                    newSize = Long.valueOf(line.remaining());
-                } else {
-                    newSize = Long.valueOf(currentSize.intValue() + line.remaining());
-                }
+                Long newSize = session.getAttachment(CURRENT_SIZE, State.Transaction)
+                    .map(currentSize -> Long.valueOf(currentSize.intValue() + line.remaining()))
+                    .orElseGet(() -> Long.valueOf(line.remaining()));
 
-                session.setAttachment("CURRENT_SIZE", newSize, State.Transaction);
+                session.setAttachment(CURRENT_SIZE, newSize, State.Transaction);
 
                 if (session.getConfiguration().getMaxMessageSize() > 0 && newSize.intValue() > session.getConfiguration().getMaxMessageSize()) {
                     // Add an item to the state to suppress
@@ -183,8 +182,8 @@ public class MailSizeEsmtpExtension implements MailParametersHook, EhloExtension
 
     @Override
     public HookResult onMessage(SMTPSession session, MailEnvelope mail) {
-        Boolean failed = (Boolean) session.getAttachment(MESG_FAILED, State.Transaction);
-        if (failed != null && failed) {
+        Optional<Boolean> failed = session.getAttachment(MESG_FAILED, State.Transaction);
+        if (failed.isPresent() && failed.get()) {
             LOGGER.error("Rejected message from {} from {} exceeding system maximum message size of {}", session.getAttachment(SMTPSession.SENDER, State.Transaction), session.getRemoteAddress().getAddress().getHostAddress(), session.getConfiguration().getMaxMessageSize());
             return QUOTA_EXCEEDED;
         } else {
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandler.java
index 2439de8..68d3181 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandler.java
@@ -22,10 +22,12 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Optional;
 import java.util.StringTokenizer;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
+import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.dsn.DSNStatus;
@@ -49,11 +51,9 @@ public class DNSRBLHandler implements RcptHook {
         
     private boolean getDetail = false;
     
-    private final String blocklistedDetail = null;
+    public static final ProtocolSession.AttachmentKey<Boolean> RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME = ProtocolSession.AttachmentKey.of("org.apache.james.smtpserver.rbl.blocklisted", Boolean.class);
     
-    public static final String RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME = "org.apache.james.smtpserver.rbl.blocklisted";
-    
-    public static final String RBL_DETAIL_MAIL_ATTRIBUTE_NAME = "org.apache.james.smtpserver.rbl.detail";
+    public static final ProtocolSession.AttachmentKey<String> RBL_DETAIL_MAIL_ATTRIBUTE_NAME = ProtocolSession.AttachmentKey.of("org.apache.james.smtpserver.rbl.detail", String.class);
 
     /**
      * Set the whitelist array
@@ -154,7 +154,7 @@ public class DNSRBLHandler implements RcptHook {
                             }
                         }
 
-                        session.setAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, "true", State.Connection);
+                        session.setAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, true, State.Connection);
                         return;
                     } else {
                         // if it is unknown, it isn't blocked
@@ -171,10 +171,11 @@ public class DNSRBLHandler implements RcptHook {
         checkDNSRBL(session, session.getRemoteAddress().getAddress().getHostAddress());
     
         if (!session.isRelayingAllowed()) {
-            String blocklisted = (String) session.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, State.Connection);
-    
-            if (blocklisted != null) { // was found in the RBL
-                if (blocklistedDetail == null) {
+            Optional<Boolean> blocklisted = session.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, State.Connection);
+            Optional<String> blocklistedDetail = session.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, State.Connection);
+
+            if (blocklisted.isPresent()) { // was found in the RBL
+                if (!blocklistedDetail.isPresent()) {
                     return HookResult.builder()
                         .hookReturnCode(HookReturnCode.deny())
                         .smtpDescription(DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.SECURITY_AUTH)
@@ -185,7 +186,7 @@ public class DNSRBLHandler implements RcptHook {
 
                     return HookResult.builder()
                         .hookReturnCode(HookReturnCode.deny())
-                        .smtpDescription(DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH) + " " + blocklistedDetail)
+                        .smtpDescription(DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH) + " " + blocklistedDetail.get())
                         .build();
                 }
                
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandler.java
index 1461a8f..f8729ec 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandler.java
@@ -20,6 +20,7 @@
 
 package org.apache.james.protocols.smtp.core.fastfail;
 
+import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookResult;
@@ -33,7 +34,7 @@ public class MaxUnknownCmdHandler implements UnknownHook {
 
     public static final int DEFAULT_MAX_UNKOWN = 5;
     
-    private static final String UNKOWN_COMMAND_COUNT = "UNKNOWN_COMMAND_COUNT";
+    private static final ProtocolSession.AttachmentKey<Integer> UNKOWN_COMMAND_COUNT = ProtocolSession.AttachmentKey.of("UNKNOWN_COMMAND_COUNT", Integer.class);
     private int maxUnknown = DEFAULT_MAX_UNKOWN;
 
     public void setMaxUnknownCmdCount(int maxUnknown) {
@@ -42,12 +43,10 @@ public class MaxUnknownCmdHandler implements UnknownHook {
     
     @Override
     public HookResult doUnknown(SMTPSession session, String command) {
-        Integer count = (Integer) session.getAttachment(UNKOWN_COMMAND_COUNT, State.Transaction);
-        if (count == null) {
-            count = 1;
-        } else {
-            count++;
-        }
+        Integer count = session.getAttachment(UNKOWN_COMMAND_COUNT, State.Transaction)
+            .map(fetchedCount -> fetchedCount + 1)
+            .orElse(1);
+
         session.setAttachment(UNKOWN_COMMAND_COUNT, count, State.Transaction);
         if (count > maxUnknown) {
             return HookResult.builder()
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandler.java
index 403490a..1abce80 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandler.java
@@ -24,6 +24,7 @@ import java.net.UnknownHostException;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
+import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.smtp.SMTPRetCode;
 import org.apache.james.protocols.smtp.SMTPSession;
@@ -39,7 +40,7 @@ import org.apache.james.protocols.smtp.hook.RcptHook;
  */
 public class ResolvableEhloHeloHandler implements RcptHook, HeloHook {
 
-    public static final String BAD_EHLO_HELO = "BAD_EHLO_HELO";
+    public static final ProtocolSession.AttachmentKey<Boolean> BAD_EHLO_HELO = ProtocolSession.AttachmentKey.of("BAD_EHLO_HELO", Boolean.class);
 
     /**
      * Check if EHLO/HELO is resolvable
@@ -50,9 +51,8 @@ public class ResolvableEhloHeloHandler implements RcptHook, HeloHook {
      *            The argument
      */
     protected void checkEhloHelo(SMTPSession session, String argument) {
-        
         if (isBadHelo(session, argument)) {
-            session.setAttachment(BAD_EHLO_HELO, "true", State.Transaction);
+            session.setAttachment(BAD_EHLO_HELO, true, State.Transaction);
         }
     }
     
@@ -74,11 +74,7 @@ public class ResolvableEhloHeloHandler implements RcptHook, HeloHook {
 
     protected boolean check(SMTPSession session,MailAddress rcpt) {
         // not reject it
-        if (session.getAttachment(BAD_EHLO_HELO, State.Transaction) == null) {
-            return false;
-        }
-
-        return true;
+        return session.getAttachment(BAD_EHLO_HELO, State.Transaction).isPresent();
     }
 
     @Override
diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/SupressDuplicateRcptHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/SupressDuplicateRcptHandler.java
index bd4cf71..f3782f6 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/SupressDuplicateRcptHandler.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/fastfail/SupressDuplicateRcptHandler.java
@@ -19,8 +19,6 @@
 
 package org.apache.james.protocols.smtp.core.fastfail;
 
-import java.util.Collection;
-
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
 import org.apache.james.protocols.api.ProtocolSession.State;
@@ -40,25 +38,23 @@ public class SupressDuplicateRcptHandler implements RcptHook {
     private static final Logger LOGGER = LoggerFactory.getLogger(SupressDuplicateRcptHandler.class);
 
     @Override
-    @SuppressWarnings("unchecked")
     public HookResult doRcpt(SMTPSession session, MaybeSender sender, MailAddress rcpt) {
-        Collection<MailAddress> rcptList = (Collection<MailAddress>) session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction);
-    
-        // Check if the recipient is already in the rcpt list
-        if (rcptList != null && rcptList.contains(rcpt)) {
-            StringBuilder responseBuffer = new StringBuilder();
-        
-            responseBuffer.append(DSNStatus.getStatus(DSNStatus.SUCCESS, DSNStatus.ADDRESS_VALID))
-                          .append(" Recipient <")
-                          .append(rcpt.toString())
-                          .append("> OK");
-            LOGGER.debug("Duplicate recipient not add to recipient list: {}", rcpt);
-            return HookResult.builder()
-                .hookReturnCode(HookReturnCode.ok())
-                .smtpReturnCode(SMTPRetCode.MAIL_OK)
-                .smtpDescription(responseBuffer.toString())
-                .build();
-        }
-        return HookResult.DECLINED;
+        return session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction)
+            .filter(rcptList -> rcptList.contains(rcpt))
+            .map(rcptList -> {
+                StringBuilder responseBuffer = new StringBuilder();
+
+                responseBuffer.append(DSNStatus.getStatus(DSNStatus.SUCCESS, DSNStatus.ADDRESS_VALID))
+                              .append(" Recipient <")
+                              .append(rcpt.toString())
+                              .append("> OK");
+                LOGGER.debug("Duplicate recipient not add to recipient list: {}", rcpt);
+                return HookResult.builder()
+                    .hookReturnCode(HookReturnCode.ok())
+                    .smtpReturnCode(SMTPRetCode.MAIL_OK)
+                    .smtpDescription(responseBuffer.toString())
+                    .build();
+            })
+            .orElse(HookResult.DECLINED);
     }
 }
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandlerTest.java
index 87c30c4..2265aad 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/DNSRBLHandlerTest.java
@@ -21,6 +21,8 @@
 package org.apache.james.protocols.smtp.core.fastfail;
 
 import static org.apache.james.protocols.api.ProtocolSession.State.Connection;
+import static org.apache.james.protocols.smtp.core.fastfail.DNSRBLHandler.RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME;
+import static org.apache.james.protocols.smtp.core.fastfail.DNSRBLHandler.RBL_DETAIL_MAIL_ATTRIBUTE_NAME;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.net.InetSocketAddress;
@@ -29,6 +31,7 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
@@ -38,6 +41,8 @@ import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.base.Preconditions;
+
 public class DNSRBLHandlerTest {
 
     private SMTPSession mockedSMTPSession;
@@ -45,10 +50,6 @@ public class DNSRBLHandlerTest {
     private String remoteIp = "127.0.0.2";
 
     private boolean relaying = false;   
-    
-    public static final String RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME = "org.apache.james.smtpserver.rbl.blocklisted";
-    
-    public static final String RBL_DETAIL_MAIL_ATTRIBUTE_NAME = "org.apache.james.smtpserver.rbl.detail";
 
     @Before
     public void setUp() throws Exception {
@@ -114,8 +115,8 @@ public class DNSRBLHandlerTest {
      */
     private void setupMockedSMTPSession(MailAddress rcpt) {
         mockedSMTPSession = new BaseFakeSMTPSession() {
-            HashMap<String,Object> sessionState = new HashMap<>();
-            HashMap<String,Object> connectionState = new HashMap<>();
+            HashMap<AttachmentKey<?>,Object> sessionState = new HashMap<>();
+            HashMap<AttachmentKey<?>,Object> connectionState = new HashMap<>();
             
             @Override
             public InetSocketAddress getRemoteAddress() {
@@ -127,7 +128,7 @@ public class DNSRBLHandlerTest {
             }
 
             @Override
-            public Map<String,Object> getState() {
+            public Map<AttachmentKey<?>,Object> getState() {
                 return sessionState;
             }
 
@@ -147,28 +148,34 @@ public class DNSRBLHandlerTest {
             }
             
             @Override
-            public Object setAttachment(String key, Object value, State state) {
+            public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+                Preconditions.checkNotNull(value, "value cannot be null");
+
+                if (state == State.Connection) {
+                    return key.convert(connectionState.put(key, value));
+                } else {
+                    return key.convert(sessionState.put(key, value));
+                }
+            }
+
+            @Override
+            public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+
                 if (state == State.Connection) {
-                    if (value == null) {
-                        return connectionState.remove(key);
-                    } else {
-                        return connectionState.put(key, value);
-                    }
+                    return key.convert(connectionState.remove(key));
                 } else {
-                    if (value == null) {
-                        return sessionState.remove(key);
-                    } else {
-                        return sessionState.put(key, value);
-                    }
+                    return key.convert(sessionState.remove(key));
                 }
             }
 
             @Override
-            public Object getAttachment(String key, State state) {
+            public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
                 if (state == State.Connection) {
-                    return connectionState.get(key);
+                    return key.convert(connectionState.get(key));
                 } else {
-                    return sessionState.get(key);
+                    return key.convert(sessionState.get(key));
                 }
             }
 
@@ -185,8 +192,8 @@ public class DNSRBLHandlerTest {
         rbl.setBlacklist(new String[] { "bl.spamcop.net." });
         rbl.setGetDetail(true);
         rbl.doRcpt(mockedSMTPSession, MaybeSender.nullSender(), new MailAddress("test@localhost"));
-        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, State.Connection)).describedAs("Details").isEqualTo("Blocked - see http://www.spamcop.net/bl.shtml?127.0.0.2");
-        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Blocked").isNotNull();
+        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, State.Connection)).describedAs("Details").contains("Blocked - see http://www.spamcop.net/bl.shtml?127.0.0.2");
+        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Blocked").isPresent();
     }
 
     // ip is blacklisted and has txt details but we don'T want to retrieve the txt record
@@ -198,8 +205,8 @@ public class DNSRBLHandlerTest {
         rbl.setBlacklist(new String[] { "bl.spamcop.net." });
         rbl.setGetDetail(false);
         rbl.doRcpt(mockedSMTPSession, MaybeSender.nullSender(), new MailAddress("test@localhost"));
-        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("No details").isNull();
-        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Blocked").isNotNull();
+        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("No details").isEmpty();
+        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Blocked").isPresent();
     }
 
     // ip is allowed to relay
@@ -212,8 +219,8 @@ public class DNSRBLHandlerTest {
         rbl.setBlacklist(new String[] { "bl.spamcop.net." });
         rbl.setGetDetail(true);
         rbl.doRcpt(mockedSMTPSession, MaybeSender.nullSender(), new MailAddress("test@localhost"));
-        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("No details").isNull();
-        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Not blocked").isNull();
+        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("No details").isEmpty();
+        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Not blocked").isEmpty();
     }
 
     // ip not on blacklist
@@ -227,8 +234,8 @@ public class DNSRBLHandlerTest {
         rbl.setBlacklist(new String[] { "bl.spamcop.net." });
         rbl.setGetDetail(true);
         rbl.doRcpt(mockedSMTPSession, MaybeSender.nullSender(), new MailAddress("test@localhost"));
-        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("No details").isNull();
-        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Not blocked").isNull();
+        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("No details").isEmpty();
+        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Not blocked").isEmpty();
     }
 
     // ip on blacklist without txt details
@@ -242,8 +249,8 @@ public class DNSRBLHandlerTest {
         rbl.setBlacklist(new String[] { "bl.spamcop.net." });
         rbl.setGetDetail(true);
         rbl.doRcpt(mockedSMTPSession, MaybeSender.nullSender(), new MailAddress("test@localhost"));
-        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, Connection)).isNull();
-        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Blocked").isNotNull();
+        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, Connection)).isEmpty();
+        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Blocked").isPresent();
     }
 
     // ip on whitelist
@@ -257,8 +264,8 @@ public class DNSRBLHandlerTest {
         rbl.setWhitelist(new String[] { "bl.spamcop.net." });
         rbl.setGetDetail(true);
         rbl.doRcpt(mockedSMTPSession, MaybeSender.nullSender(), new MailAddress("test@localhost"));
-        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, Connection)).isNull();
-        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Not blocked").isNull();
+        assertThat(mockedSMTPSession.getAttachment(RBL_DETAIL_MAIL_ATTRIBUTE_NAME, Connection)).isEmpty();
+        assertThat(mockedSMTPSession.getAttachment(RBL_BLOCKLISTED_MAIL_ATTRIBUTE_NAME, Connection)).withFailMessage("Not blocked").isEmpty();
     }
    
 
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxRcptHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxRcptHandlerTest.java
index c9eb470..72ee259 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxRcptHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxRcptHandlerTest.java
@@ -35,10 +35,10 @@ public class MaxRcptHandlerTest {
     
     private SMTPSession setupMockedSession(final int rcptCount) {
         return new BaseFakeSMTPSession() {
-            HashMap<String,Object> state = new HashMap<>();
+            HashMap<AttachmentKey<?>, Object> state = new HashMap<>();
 
             @Override
-            public Map<String,Object> getState() {
+            public Map<AttachmentKey<?>, Object> getState() {
                 return state;
             }
 
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandlerTest.java
index 128ce7d..98f9412 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/MaxUnknownCmdHandlerTest.java
@@ -24,45 +24,57 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookReturnCode;
 import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
 import org.junit.Test;
 
+import com.google.common.base.Preconditions;
+
 public class MaxUnknownCmdHandlerTest {
 
     
     @Test
     public void testRejectAndClose() throws Exception {
         SMTPSession session = new BaseFakeSMTPSession() {
-            private final HashMap<String,Object> map = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> map = new HashMap<>();
 
             @Override
-            public Map<String,Object> getState() {
+            public Map<AttachmentKey<?>, Object> getState() {
                 return map;
             }
 
             @Override
-            public Object setAttachment(String key, Object value, State state) {
+            public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+                Preconditions.checkNotNull(value, "value cannot be null");
+
                 if (state == State.Connection) {
                     throw new UnsupportedOperationException();
+                } else {
+                    return key.convert(map.put(key, value));
+                }
+            }
 
+            @Override
+            public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+
+                if (state == State.Connection) {
+                    throw new UnsupportedOperationException();
                 } else {
-                    if (value == null) {
-                        return map.remove(key);
-                    } else {
-                        return map.put(key, value);
-                    }
+                    return key.convert(map.remove(key));
                 }
             }
 
             @Override
-            public Object getAttachment(String key, State state) {
+            public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
                 if (state == State.Connection) {
                     throw new UnsupportedOperationException();
                 } else {
-                    return map.get(key);
+                    return key.convert(map.get(key));
                 }
             }
         };
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandlerTest.java
index 320f6a1..cf2052b 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ResolvableEhloHeloHandlerTest.java
@@ -27,6 +27,7 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
@@ -36,6 +37,8 @@ import org.apache.james.protocols.smtp.hook.HookReturnCode;
 import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
 import org.junit.Test;
 
+import com.google.common.base.Preconditions;
+
 public class ResolvableEhloHeloHandlerTest {
 
     public static final String INVALID_HOST = "foo.bar";
@@ -48,8 +51,8 @@ public class ResolvableEhloHeloHandlerTest {
 
         return new BaseFakeSMTPSession() {
 
-            HashMap<String,Object> connectionMap = new HashMap<>();
-            HashMap<String,Object> map = new HashMap<>();
+            HashMap<AttachmentKey<?>, Object> connectionMap = new HashMap<>();
+            HashMap<AttachmentKey<?>, Object> map = new HashMap<>();
 
             @Override
             public boolean isAuthSupported() {
@@ -62,7 +65,7 @@ public class ResolvableEhloHeloHandlerTest {
             }
 
             @Override
-            public Map<String,Object> getConnectionState() {
+            public Map<AttachmentKey<?>, Object> getConnectionState() {
                 return connectionMap;
             }
 
@@ -72,33 +75,39 @@ public class ResolvableEhloHeloHandlerTest {
             }
 
             @Override
-            public Map<String,Object> getState() {
+            public Map<AttachmentKey<?>, Object> getState() {
                 return map;
             }
 
             @Override
-            public Object setAttachment(String key, Object value, State state) {
+            public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+                Preconditions.checkNotNull(value, "value cannot be null");
+
+                if (state == State.Connection) {
+                    return key.convert(connectionMap.put(key, value));
+                } else {
+                    return key.convert(map.put(key, value));
+                }
+            }
+
+            @Override
+            public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+
                 if (state == State.Connection) {
-                    if (value == null) {
-                        return connectionMap.remove(key);
-                    } else {
-                        return connectionMap.put(key, value);
-                    }
+                    return key.convert(connectionMap.remove(key));
                 } else {
-                    if (value == null) {
-                        return map.remove(key);
-                    } else {
-                        return connectionMap.put(key, value);
-                    }
+                    return key.convert(map.remove(key));
                 }
             }
 
             @Override
-            public Object getAttachment(String key, State state) {
+            public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
                 if (state == State.Connection) {
-                    return connectionMap.get(key);
+                    return key.convert(connectionMap.get(key));
                 } else {
-                    return connectionMap.get(key);
+                    return key.convert(map.get(key));
                 }
             }
 
@@ -122,11 +131,11 @@ public class ResolvableEhloHeloHandlerTest {
     @Test
     public void testRejectInvalidHelo() throws Exception {
         MailAddress mailAddress = new MailAddress("test@localhost");
-        SMTPSession session = setupMockSession(INVALID_HOST,false,false,null,mailAddress);
+        SMTPSession session = setupMockSession(INVALID_HOST, false, false, null, mailAddress);
         ResolvableEhloHeloHandler handler = createHandler();
         
         handler.doHelo(session, INVALID_HOST);
-        assertThat(session.getAttachment(BAD_EHLO_HELO, Transaction)).withFailMessage("Invalid HELO").isNotNull();
+        assertThat(session.getAttachment(BAD_EHLO_HELO, Transaction)).withFailMessage("Invalid HELO").isPresent();
 
         HookReturnCode result = handler.doRcpt(session, MaybeSender.nullSender(), mailAddress).getResult();
         assertThat(HookReturnCode.deny()).describedAs("Reject").isEqualTo(result);
@@ -135,12 +144,12 @@ public class ResolvableEhloHeloHandlerTest {
     @Test
     public void testNotRejectValidHelo() throws Exception {
         MailAddress mailAddress = new MailAddress("test@localhost");
-        SMTPSession session = setupMockSession(VALID_HOST,false,false,null,mailAddress);
+        SMTPSession session = setupMockSession(VALID_HOST, false, false, null, mailAddress);
         ResolvableEhloHeloHandler handler = createHandler();
 
   
         handler.doHelo(session, VALID_HOST);
-        assertThat(session.getAttachment(BAD_EHLO_HELO, Transaction)).withFailMessage("Valid HELO").isNull();
+        assertThat(session.getAttachment(BAD_EHLO_HELO, Transaction)).withFailMessage("Valid HELO").isEmpty();
 
         HookReturnCode result = handler.doRcpt(session, MaybeSender.nullSender(), mailAddress).getResult();
         assertThat(HookReturnCode.declined()).describedAs("Not reject").isEqualTo(result);
@@ -154,7 +163,7 @@ public class ResolvableEhloHeloHandlerTest {
 
 
         handler.doHelo(session, INVALID_HOST);
-        assertThat(session.getAttachment(BAD_EHLO_HELO, Transaction)).withFailMessage("Value stored").isNotNull();
+        assertThat(session.getAttachment(BAD_EHLO_HELO, Transaction)).withFailMessage("Value stored").isPresent();
 
 
         HookReturnCode result = handler.doRcpt(session, MaybeSender.nullSender(), mailAddress).getResult();
@@ -165,16 +174,15 @@ public class ResolvableEhloHeloHandlerTest {
     @Test
     public void testRejectRelay() throws Exception {
         MailAddress mailAddress = new MailAddress("test@localhost");
-        SMTPSession session = setupMockSession(INVALID_HOST,true,false,null,mailAddress);
+        SMTPSession session = setupMockSession(INVALID_HOST, true, false, null, mailAddress);
         ResolvableEhloHeloHandler handler = createHandler();
 
 
         handler.doHelo(session, INVALID_HOST);
-        assertThat(session.getAttachment(BAD_EHLO_HELO, Transaction)).withFailMessage("Value stored").isNotNull();
+        assertThat(session.getAttachment(BAD_EHLO_HELO, Transaction)).withFailMessage("Value stored").isPresent();
 
 
         HookReturnCode result = handler.doRcpt(session, MaybeSender.nullSender(), mailAddress).getResult();
         assertThat(HookReturnCode.deny()).describedAs("Reject").isEqualTo(result);
     }
 }
-    
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ValidSenderDomainHandlerTest.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ValidSenderDomainHandlerTest.java
index 407f1ca..685b4f2 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ValidSenderDomainHandlerTest.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/fastfail/ValidSenderDomainHandlerTest.java
@@ -23,6 +23,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
@@ -32,6 +33,8 @@ import org.apache.james.protocols.smtp.hook.HookReturnCode;
 import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
 import org.junit.Test;
 
+import com.google.common.base.Preconditions;
+
 public class ValidSenderDomainHandlerTest {
     
     private ValidSenderDomainHandler createHandler() {
@@ -48,11 +51,10 @@ public class ValidSenderDomainHandlerTest {
     
     private SMTPSession setupMockedSession(final MailAddress sender) {
         return new BaseFakeSMTPSession() {
-            HashMap<String,Object> map = new HashMap<>();
+            Map<AttachmentKey<?>, Object> map = new HashMap<>();
 
             @Override
-            public Map<String,Object> getState() {
-
+            public Map<AttachmentKey<?>, Object> getState() {
                 map.put(SMTPSession.SENDER, MaybeSender.of(sender));
 
                 return map;
@@ -64,25 +66,34 @@ public class ValidSenderDomainHandlerTest {
             }
 
             @Override
-            public Object setAttachment(String key, Object value, State state) {
+            public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+                Preconditions.checkNotNull(value, "value cannot be null");
+
                 if (state == State.Connection) {
                     throw new UnsupportedOperationException();
+                } else {
+                    return key.convert(getState().put(key, value));
+                }
+            }
+
+            @Override
+            public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
 
+                if (state == State.Connection) {
+                    throw new UnsupportedOperationException();
                 } else {
-                    if (value == null) {
-                        return getState().remove(key);
-                    } else {
-                        return getState().put(key, value);
-                    }
+                    return key.convert(getState().remove(key));
                 }
             }
 
             @Override
-            public Object getAttachment(String key, State state) {
+            public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
                 if (state == State.Connection) {
                     throw new UnsupportedOperationException();
                 } else {
-                    return getState().get(key);
+                    return key.convert(getState().get(key));
                 }
             }
 
@@ -103,7 +114,7 @@ public class ValidSenderDomainHandlerTest {
     public void testInvalidSenderDomainReject() throws Exception {
         ValidSenderDomainHandler handler = createHandler();
         SMTPSession session = setupMockedSession(new MailAddress("invalid@invalid"));
-        MaybeSender sender = (MaybeSender) session.getAttachment(SMTPSession.SENDER, State.Transaction);
+        MaybeSender sender = session.getAttachment(SMTPSession.SENDER, State.Transaction).get();
         HookReturnCode response = handler.doMail(session, sender).getResult();
         
         assertThat(HookReturnCode.deny()).describedAs("Blocked cause we use reject action").isEqualTo(response);
diff --git a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/utils/BaseFakeSMTPSession.java b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/utils/BaseFakeSMTPSession.java
index a6c8af1..af819ee 100644
--- a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/utils/BaseFakeSMTPSession.java
+++ b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/utils/BaseFakeSMTPSession.java
@@ -23,6 +23,7 @@ package org.apache.james.protocols.smtp.utils;
 import java.net.InetSocketAddress;
 import java.nio.charset.Charset;
 import java.util.Map;
+import java.util.Optional;
 
 import org.apache.james.core.Username;
 import org.apache.james.protocols.api.ProtocolSession;
@@ -52,7 +53,7 @@ public class BaseFakeSMTPSession implements SMTPSession {
     }
 
     @Override
-    public Map<String, Object> getConnectionState() {
+    public Map<AttachmentKey<?>, Object> getConnectionState() {
         throw new UnsupportedOperationException("Unimplemented Stub Method");
     }
 
@@ -67,7 +68,7 @@ public class BaseFakeSMTPSession implements SMTPSession {
     }
 
     @Override
-    public Map<String, Object> getState() {
+    public Map<AttachmentKey<?>, Object> getState() {
         throw new UnsupportedOperationException("Unimplemented Stub Method");
     }
 
@@ -147,12 +148,17 @@ public class BaseFakeSMTPSession implements SMTPSession {
     }
 
     @Override
-    public Object setAttachment(String key, Object value, State state) {
+    public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
         throw new UnsupportedOperationException("Unimplemented Stub Method");
     }
 
     @Override
-    public Object getAttachment(String key, State state) {
+    public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+        throw new UnsupportedOperationException("Unimplemented Stub Method");
+    }
+
+    @Override
+    public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
         throw new UnsupportedOperationException("Unimplemented Stub Method");
     }
 
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/DataLineJamesMessageHookHandler.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/DataLineJamesMessageHookHandler.java
index 67c1125..fe3ac7c 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/DataLineJamesMessageHookHandler.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/DataLineJamesMessageHookHandler.java
@@ -74,7 +74,8 @@ public class DataLineJamesMessageHookHandler implements DataLineFilter, Extensib
         byte[] line = new byte[lineByteBuffer.remaining()];
         lineByteBuffer.get(line, 0, line.length);
 
-        MimeMessageInputStreamSource mmiss = (MimeMessageInputStreamSource) session.getAttachment(SMTPConstants.DATA_MIMEMESSAGE_STREAMSOURCE, State.Transaction);
+        MimeMessageInputStreamSource mmiss = session.getAttachment(SMTPConstants.DATA_MIMEMESSAGE_STREAMSOURCE, State.Transaction)
+            .orElseThrow(() -> new RuntimeException("'" + SMTPConstants.DATA_MIMEMESSAGE_STREAMSOURCE.asString() + "' has not been filled."));
 
         try {
             OutputStream out = mmiss.getWritableOutputStream();
@@ -85,9 +86,8 @@ public class DataLineJamesMessageHookHandler implements DataLineFilter, Extensib
                 out.flush();
                 out.close();
 
-                @SuppressWarnings("unchecked")
-                List<MailAddress> recipientCollection = (List<MailAddress>) session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction);
-                MaybeSender sender = (MaybeSender) session.getAttachment(SMTPSession.SENDER, State.Transaction);
+                List<MailAddress> recipientCollection = session.getAttachment(SMTPSession.RCPT_LIST, State.Transaction).orElse(ImmutableList.of());
+                MaybeSender sender = session.getAttachment(SMTPSession.SENDER, State.Transaction).orElse(MaybeSender.nullSender());
 
                 MailImpl mail = MailImpl.builder()
                     .name(MailImpl.getId())
@@ -140,7 +140,8 @@ public class DataLineJamesMessageHookHandler implements DataLineFilter, Extensib
     protected Response processExtensions(SMTPSession session, Mail mail) {
         if (mail != null && messageHandlers != null) {
             try {
-                MimeMessageInputStreamSource mmiss = (MimeMessageInputStreamSource) session.getAttachment(SMTPConstants.DATA_MIMEMESSAGE_STREAMSOURCE, State.Transaction);
+                MimeMessageInputStreamSource mmiss = session.getAttachment(SMTPConstants.DATA_MIMEMESSAGE_STREAMSOURCE, State.Transaction)
+                    .orElseThrow(() -> new RuntimeException("'" + SMTPConstants.DATA_MIMEMESSAGE_STREAMSOURCE.asString() + "' has not been filled."));
                 OutputStream out;
                 out = mmiss.getWritableOutputStream();
                 for (MessageHook rawHandler : mHandlers) {
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SMTPConstants.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SMTPConstants.java
index b401721..3b062e3 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SMTPConstants.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SMTPConstants.java
@@ -19,12 +19,16 @@
 
 package org.apache.james.smtpserver;
 
+import org.apache.james.protocols.api.ProtocolSession;
+import org.apache.james.server.core.MimeMessageInputStreamSource;
+import org.apache.mailet.Mail;
+
 /**
  * Constants which are used within SMTP Session
  */
 public interface SMTPConstants {
 
-    String DATA_MIMEMESSAGE_STREAMSOURCE = "org.apache.james.core.DataCmdHandler.DATA_MIMEMESSAGE_STREAMSOURCE";
-    String MAIL = "MAIL";
+    ProtocolSession.AttachmentKey<MimeMessageInputStreamSource> DATA_MIMEMESSAGE_STREAMSOURCE = ProtocolSession.AttachmentKey.of("org.apache.james.core.DataCmdHandler.DATA_MIMEMESSAGE_STREAMSOURCE", MimeMessageInputStreamSource.class);
+    ProtocolSession.AttachmentKey<Mail> MAIL = ProtocolSession.AttachmentKey.of("MAIL", Mail.class);
 
 }
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SPFHandler.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SPFHandler.java
index ee4edf9..f7c0e5c 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SPFHandler.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SPFHandler.java
@@ -18,6 +18,8 @@
  ****************************************************************/
 package org.apache.james.smtpserver.fastfail;
 
+import java.util.Optional;
+
 import javax.inject.Inject;
 
 import org.apache.commons.configuration2.Configuration;
@@ -29,6 +31,7 @@ import org.apache.james.jspf.core.exceptions.SPFErrorConstants;
 import org.apache.james.jspf.executor.SPFResult;
 import org.apache.james.jspf.impl.DefaultSPF;
 import org.apache.james.jspf.impl.SPF;
+import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.api.handler.ProtocolHandler;
 import org.apache.james.protocols.smtp.SMTPRetCode;
@@ -59,13 +62,13 @@ public class SPFHandler implements JamesMessageHook, MailHook, RcptHook, Protoco
      */
     private final Logger serviceLog = FALLBACK_LOG;
 
-    private static final String SPF_BLOCKLISTED = "SPF_BLOCKLISTED";
+    private static final ProtocolSession.AttachmentKey<Boolean> SPF_BLOCKLISTED = ProtocolSession.AttachmentKey.of("SPF_BLOCKLISTED", Boolean.class);
 
-    private static final String SPF_DETAIL = "SPF_DETAIL";
+    private static final ProtocolSession.AttachmentKey<String> SPF_DETAIL = ProtocolSession.AttachmentKey.of("SPF_DETAIL", String.class);
 
-    private static final String SPF_TEMPBLOCKLISTED = "SPF_TEMPBLOCKLISTED";
+    private static final ProtocolSession.AttachmentKey<Boolean> SPF_TEMPBLOCKLISTED = ProtocolSession.AttachmentKey.of("SPF_TEMPBLOCKLISTED", Boolean.class);
 
-    private static final String SPF_HEADER = "SPF_HEADER";
+    private static final ProtocolSession.AttachmentKey<String> SPF_HEADER = ProtocolSession.AttachmentKey.of("SPF_HEADER", String.class);
 
     private static final AttributeName SPF_HEADER_MAIL_ATTRIBUTE_NAME = AttributeName.of("org.apache.james.spf.header");
 
@@ -114,16 +117,16 @@ public class SPFHandler implements JamesMessageHook, MailHook, RcptHook, Protoco
      *            SMTP session object
      */
     private void doSPFCheck(SMTPSession session, MaybeSender sender) {
-        String heloEhlo = (String) session.getAttachment(SMTPSession.CURRENT_HELO_NAME, State.Transaction);
+        Optional<String> heloEhlo = session.getAttachment(SMTPSession.CURRENT_HELO_NAME, State.Transaction);
 
         // We have no Sender or HELO/EHLO yet return false
-        if (sender.isNullSender() || heloEhlo == null) {
+        if (sender.isNullSender() || !heloEhlo.isPresent()) {
             LOGGER.info("No Sender or HELO/EHLO present");
         } else {
 
             String ip = session.getRemoteAddress().getAddress().getHostAddress();
 
-            SPFResult result = spf.checkSPF(ip, sender.asString(), heloEhlo);
+            SPFResult result = spf.checkSPF(ip, sender.asString(), heloEhlo.get());
 
             String spfResult = result.getResult();
 
@@ -141,10 +144,10 @@ public class SPFHandler implements JamesMessageHook, MailHook, RcptHook, Protoco
                     explanation = "Block caused by an invalid SPF record";
                 }
                 session.setAttachment(SPF_DETAIL, explanation, State.Transaction);
-                session.setAttachment(SPF_BLOCKLISTED, "true", State.Transaction);
+                session.setAttachment(SPF_BLOCKLISTED, true, State.Transaction);
 
             } else if (spfResult.equals(SPFErrorConstants.TEMP_ERROR_CONV)) {
-                session.setAttachment(SPF_TEMPBLOCKLISTED, "true", State.Transaction);
+                session.setAttachment(SPF_TEMPBLOCKLISTED, true, State.Transaction);
             }
 
         }
@@ -155,13 +158,13 @@ public class SPFHandler implements JamesMessageHook, MailHook, RcptHook, Protoco
     public HookResult doRcpt(SMTPSession session, MaybeSender sender, MailAddress rcpt) {
         if (!session.isRelayingAllowed()) {
             // Check if session is blocklisted
-            if (session.getAttachment(SPF_BLOCKLISTED, State.Transaction) != null) {
+            if (session.getAttachment(SPF_BLOCKLISTED, State.Transaction).isPresent()) {
 
                 return HookResult.builder()
                     .hookReturnCode(HookReturnCode.deny())
-                    .smtpDescription(DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.SECURITY_AUTH) + " " + session.getAttachment(SPF_TEMPBLOCKLISTED, State.Transaction))
+                    .smtpDescription(DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.SECURITY_AUTH) + " " + session.getAttachment(SPF_TEMPBLOCKLISTED, State.Transaction).orElse(false))
                     .build();
-            } else if (session.getAttachment(SPF_TEMPBLOCKLISTED, State.Transaction) != null) {
+            } else if (session.getAttachment(SPF_TEMPBLOCKLISTED, State.Transaction).isPresent()) {
                 return HookResult.builder()
                     .hookReturnCode(HookReturnCode.denySoft())
                     .smtpReturnCode(SMTPRetCode.LOCAL_ERROR)
@@ -277,7 +280,7 @@ public class SPFHandler implements JamesMessageHook, MailHook, RcptHook, Protoco
     @Override
     public HookResult onMessage(SMTPSession session, Mail mail) {
         // Store the spf header as attribute for later using
-        mail.setAttribute(new Attribute(SPF_HEADER_MAIL_ATTRIBUTE_NAME, AttributeValue.of((String) session.getAttachment(SPF_HEADER, State.Transaction))));
+        mail.setAttribute(new Attribute(SPF_HEADER_MAIL_ATTRIBUTE_NAME, AttributeValue.of(session.getAttachment(SPF_HEADER, State.Transaction).get())));
 
         return null;
     }
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/URIRBLHandler.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/URIRBLHandler.java
index d2b9dc6..c48d3a2 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/URIRBLHandler.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/URIRBLHandler.java
@@ -24,6 +24,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Optional;
 
 import javax.inject.Inject;
 import javax.mail.MessagingException;
@@ -35,6 +36,7 @@ import javax.mail.internet.MimePart;
 import org.apache.commons.configuration2.Configuration;
 import org.apache.commons.configuration2.ex.ConfigurationException;
 import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.protocols.api.ProtocolSession;
 import org.apache.james.protocols.api.ProtocolSession.State;
 import org.apache.james.protocols.api.handler.ProtocolHandler;
 import org.apache.james.protocols.smtp.SMTPSession;
@@ -55,9 +57,9 @@ public class URIRBLHandler implements JamesMessageHook, ProtocolHandler {
     /** This log is the fall back shared by all instances */
     private static final Logger LOGGER = LoggerFactory.getLogger(URIRBLHandler.class);
 
-    private static final String LISTED_DOMAIN = "LISTED_DOMAIN";
+    private static final ProtocolSession.AttachmentKey<String> LISTED_DOMAIN = ProtocolSession.AttachmentKey.of("LISTED_DOMAIN", String.class);
 
-    private static final String URBLSERVER = "URBL_SERVER";
+    private static final ProtocolSession.AttachmentKey<String> URBLSERVER = ProtocolSession.AttachmentKey.of("URBL_SERVER", String.class);
 
     private DNSService dnsService;
 
@@ -108,13 +110,13 @@ public class URIRBLHandler implements JamesMessageHook, ProtocolHandler {
     @Override
     public HookResult onMessage(SMTPSession session, Mail mail) {
         if (check(session, mail)) {
-            String uRblServer = (String) session.getAttachment(URBLSERVER, State.Transaction);
-            String target = (String) session.getAttachment(LISTED_DOMAIN, State.Transaction);
+            Optional<String> uRblServer = session.getAttachment(URBLSERVER, State.Transaction);
+            Optional<String> target = session.getAttachment(LISTED_DOMAIN, State.Transaction);
             String detail = null;
 
             // we should try to retrieve details
-            if (getDetail) {
-                Collection<String> txt = dnsService.findTXTRecords(target + "." + uRblServer);
+            if (uRblServer.isPresent() && target.isPresent() && getDetail) {
+                Collection<String> txt = dnsService.findTXTRecords(target.get() + "." + uRblServer.get());
 
                 // Check if we found a txt record
                 if (!txt.isEmpty()) {
@@ -127,12 +129,12 @@ public class URIRBLHandler implements JamesMessageHook, ProtocolHandler {
             if (detail != null) {
                 return HookResult.builder()
                     .hookReturnCode(HookReturnCode.deny())
-                    .smtpDescription(DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.SECURITY_OTHER) + "Rejected: message contains domain " + target + " listed by " + uRblServer + " . Details: " + detail)
+                    .smtpDescription(DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.SECURITY_OTHER) + "Rejected: message contains domain " + target.get() + " listed by " + uRblServer + " . Details: " + detail)
                     .build();
             } else {
                 return HookResult.builder()
                     .hookReturnCode(HookReturnCode.deny())
-                    .smtpDescription(DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.SECURITY_OTHER) + " Rejected: message contains domain " + target + " listed by " + uRblServer)
+                    .smtpDescription(DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.SECURITY_OTHER) + " Rejected: message contains domain " + target.orElse("[target not set]") + " listed by " + uRblServer)
                     .build();
             }
 
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/netty/SMTPChannelUpstreamHandler.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/netty/SMTPChannelUpstreamHandler.java
index 6ad881d..6933c2b 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/netty/SMTPChannelUpstreamHandler.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/netty/SMTPChannelUpstreamHandler.java
@@ -76,8 +76,8 @@ public class SMTPChannelUpstreamHandler extends BasicChannelUpstreamHandler {
         SMTPSession smtpSession = (SMTPSession) ctx.getAttachment();
 
         if (smtpSession != null) {
-            LifecycleUtil.dispose(smtpSession.getAttachment(SMTPConstants.MAIL, State.Transaction));
-            LifecycleUtil.dispose(smtpSession.getAttachment(SMTPConstants.DATA_MIMEMESSAGE_STREAMSOURCE, State.Transaction));
+            smtpSession.getAttachment(SMTPConstants.MAIL, State.Transaction).ifPresent(LifecycleUtil::dispose);
+            smtpSession.getAttachment(SMTPConstants.DATA_MIMEMESSAGE_STREAMSOURCE, State.Transaction).ifPresent(LifecycleUtil::dispose);
         }
 
         super.cleanup(ctx);
diff --git a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SPFHandlerTest.java b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SPFHandlerTest.java
index 9db776b..9349d6d 100644
--- a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SPFHandlerTest.java
+++ b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SPFHandlerTest.java
@@ -23,6 +23,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Optional;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
@@ -36,6 +37,8 @@ import org.apache.james.smtpserver.fastfail.SPFHandler;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.base.Preconditions;
+
 public class SPFHandlerTest {
 
     private DNSService mockedDnsService;
@@ -128,32 +131,40 @@ public class SPFHandlerTest {
     private void setupMockedSMTPSession(String ip, final String helo) {
         mockedSMTPSession = new BaseFakeSMTPSession() {
 
-            private final HashMap<String, Object> sstate = new HashMap<>();
-            private final HashMap<String, Object> connectionState = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> sessionState = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> connectionState = new HashMap<>();
 
             @Override
-            public Object setAttachment(String key, Object value, State state) {
+            public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+                Preconditions.checkNotNull(value, "value cannot be null");
+
+                if (state == State.Connection) {
+                    return key.convert(connectionState.put(key, value));
+                } else {
+                    return key.convert(sessionState.put(key, value));
+                }
+            }
+
+            @Override
+            public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+
                 if (state == State.Connection) {
-                    if (value == null) {
-                        return connectionState.remove(key);
-                    }
-                    return connectionState.put(key, value);
+                    return key.convert(connectionState.remove(key));
                 } else {
-                    if (value == null) {
-                        return sstate.remove(key);
-                    }
-                    return sstate.put(key, value);
+                    return key.convert(sessionState.remove(key));
                 }
             }
 
             @Override
-            public Object getAttachment(String key, State state) {
-                sstate.put(SMTPSession.CURRENT_HELO_NAME, helo);
+            public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
+                sessionState.put(SMTPSession.CURRENT_HELO_NAME, helo);
 
                 if (state == State.Connection) {
-                    return connectionState.get(key);
+                    return key.convert(connectionState.get(key));
                 } else {
-                    return sstate.get(key);
+                    return key.convert(sessionState.get(key));
                 }
             }
 
diff --git a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SpamAssassinHandlerTest.java b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SpamAssassinHandlerTest.java
index e650611..6fe930e 100644
--- a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SpamAssassinHandlerTest.java
+++ b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/SpamAssassinHandlerTest.java
@@ -22,6 +22,7 @@ import static org.apache.james.spamassassin.SpamAssassinResult.STATUS_MAIL;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.HashMap;
+import java.util.Optional;
 
 import javax.mail.MessagingException;
 import javax.mail.internet.AddressException;
@@ -46,6 +47,8 @@ import org.apache.mailet.base.test.FakeMail;
 import org.junit.Rule;
 import org.junit.Test;
 
+import com.google.common.base.Preconditions;
+
 public class SpamAssassinHandlerTest {
 
     private static final String SPAMD_HOST = "localhost";
@@ -59,36 +62,44 @@ public class SpamAssassinHandlerTest {
 
         return new BaseFakeSMTPSession() {
 
-            private final HashMap<String, Object> sstate = new HashMap<>();
-            private final HashMap<String, Object> connectionState = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> sessionState = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> connectionState = new HashMap<>();
             private boolean relayingAllowed;
 
             @Override
-            public Object setAttachment(String key, Object value, State state) {
+            public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+                Preconditions.checkNotNull(value, "value cannot be null");
+
+                if (state == State.Connection) {
+                    return key.convert(connectionState.put(key, value));
+                } else {
+                    return key.convert(sessionState.put(key, value));
+                }
+            }
+
+            @Override
+            public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+
                 if (state == State.Connection) {
-                    if (value == null) {
-                        return connectionState.remove(key);
-                    }
-                    return connectionState.put(key, value);
+                    return key.convert(connectionState.remove(key));
                 } else {
-                    if (value == null) {
-                        return sstate.remove(key);
-                    }
-                    return sstate.put(key, value);
+                    return key.convert(sessionState.remove(key));
                 }
             }
 
             @Override
-            public Object getAttachment(String key, State state) {
+            public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
                 try {
-                    sstate.put(SMTPSession.SENDER, MaybeSender.of(new MailAddress("sender@james.apache.org")));
+                    sessionState.put(SMTPSession.SENDER, MaybeSender.of(new MailAddress("sender@james.apache.org")));
                 } catch (AddressException e) {
                     throw new RuntimeException(e);
                 }
                 if (state == State.Connection) {
-                    return connectionState.get(key);
+                    return key.convert(connectionState.get(key));
                 } else {
-                    return sstate.get(key);
+                    return key.convert(sessionState.get(key));
                 }
             }
 
diff --git a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/URIRBLHandlerTest.java b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/URIRBLHandlerTest.java
index b8890aa..af14370 100644
--- a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/URIRBLHandlerTest.java
+++ b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/URIRBLHandlerTest.java
@@ -27,6 +27,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Optional;
 
 import javax.mail.MessagingException;
 import javax.mail.internet.AddressException;
@@ -46,6 +47,8 @@ import org.apache.mailet.Mail;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.Test;
 
+import com.google.common.base.Preconditions;
+
 public class URIRBLHandlerTest {
 
     private static final String BAD_DOMAIN1 = "bad.domain.de";
@@ -61,36 +64,44 @@ public class URIRBLHandlerTest {
 
             private boolean relayingAllowed;
 
-            private final HashMap<String, Object> sstate = new HashMap<>();
-            private final HashMap<String, Object> connectionState = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> sessionState = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> connectionState = new HashMap<>();
 
             @Override
-            public Object setAttachment(String key, Object value, State state) {
+            public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+                Preconditions.checkNotNull(value, "value cannot be null");
+
+                if (state == State.Connection) {
+                    return key.convert(connectionState.put(key, value));
+                } else {
+                    return key.convert(sessionState.put(key, value));
+                }
+            }
+
+            @Override
+            public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+
                 if (state == State.Connection) {
-                    if (value == null) {
-                        return connectionState.remove(key);
-                    }
-                    return connectionState.put(key, value);
+                    return key.convert(connectionState.remove(key));
                 } else {
-                    if (value == null) {
-                        return sstate.remove(key);
-                    }
-                    return sstate.put(key, value);
+                    return key.convert(sessionState.remove(key));
                 }
             }
 
             @Override
-            public Object getAttachment(String key, State state) {
+            public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
                 try {
-                    sstate.put(SMTPSession.SENDER, MaybeSender.of(new MailAddress("sender@james.apache.org")));
+                    sessionState.put(SMTPSession.SENDER, MaybeSender.of(new MailAddress("sender@james.apache.org")));
                 } catch (AddressException e) {
                     throw new RuntimeException(e);
                 }
 
                 if (state == State.Connection) {
-                    return connectionState.get(key);
+                    return key.convert(connectionState.get(key));
                 } else {
-                    return sstate.get(key);
+                    return key.convert(sessionState.get(key));
                 }
             }
 
diff --git a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/ValidRcptHandlerTest.java b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/ValidRcptHandlerTest.java
index 97ee1a1..45bc31b 100644
--- a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/ValidRcptHandlerTest.java
+++ b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/ValidRcptHandlerTest.java
@@ -23,6 +23,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 
 import java.util.HashMap;
+import java.util.Optional;
 
 import org.apache.james.core.Domain;
 import org.apache.james.core.MailAddress;
@@ -43,6 +44,8 @@ import org.apache.james.user.memory.MemoryUsersRepository;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.google.common.base.Preconditions;
+
 public class ValidRcptHandlerTest {
     private static final Username VALID_USER = Username.of("postmaster");
     private static final String INVALID_USER = "invalid";
@@ -85,30 +88,38 @@ public class ValidRcptHandlerTest {
                 return relayingAllowed;
             }
             
-            private final HashMap<String, Object> sstate = new HashMap<>();
-            private final HashMap<String, Object> connectionState = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> sessionState = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> connectionState = new HashMap<>();
 
             @Override
-            public Object setAttachment(String key, Object value, State state) {
+            public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+                Preconditions.checkNotNull(value, "value cannot be null");
+
+                if (state == State.Connection) {
+                    return key.convert(connectionState.put(key, value));
+                } else {
+                    return key.convert(sessionState.put(key, value));
+                }
+            }
+
+            @Override
+            public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+
                 if (state == State.Connection) {
-                    if (value == null) {
-                        return connectionState.remove(key);
-                    }
-                    return connectionState.put(key, value);
+                    return key.convert(connectionState.remove(key));
                 } else {
-                    if (value == null) {
-                        return sstate.remove(key);
-                    }
-                    return sstate.put(key, value);
+                    return key.convert(sessionState.remove(key));
                 }
             }
 
             @Override
-            public Object getAttachment(String key, State state) {
+            public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
                 if (state == State.Connection) {
-                    return connectionState.get(key);
+                    return key.convert(connectionState.get(key));
                 } else {
-                    return sstate.get(key);
+                    return key.convert(sessionState.get(key));
                 }
             }
         };
diff --git a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/ValidRcptMXTest.java b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/ValidRcptMXTest.java
index be784d7..ee29e3f 100644
--- a/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/ValidRcptMXTest.java
+++ b/server/protocols/protocols-smtp/src/test/java/org/apache/james/smtpserver/ValidRcptMXTest.java
@@ -21,6 +21,7 @@ package org.apache.james.smtpserver;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.HashMap;
+import java.util.Optional;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
@@ -32,6 +33,7 @@ import org.apache.james.protocols.smtp.utils.BaseFakeSMTPSession;
 import org.apache.james.smtpserver.fastfail.ValidRcptMX;
 import org.junit.Test;
 
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 
 public class ValidRcptMXTest {
@@ -41,30 +43,38 @@ public class ValidRcptMXTest {
     private SMTPSession setupMockedSMTPSession(MailAddress rcpt) {
         return new BaseFakeSMTPSession() {
 
-            private final HashMap<String, Object> sstate = new HashMap<>();
-            private final HashMap<String, Object> connectionState = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> sessionState = new HashMap<>();
+            private final HashMap<AttachmentKey<?>, Object> connectionState = new HashMap<>();
 
             @Override
-            public Object setAttachment(String key, Object value, State state) {
+            public <T> Optional<T> setAttachment(AttachmentKey<T> key, T value, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+                Preconditions.checkNotNull(value, "value cannot be null");
+
+                if (state == State.Connection) {
+                    return key.convert(connectionState.put(key, value));
+                } else {
+                    return key.convert(sessionState.put(key, value));
+                }
+            }
+
+            @Override
+            public <T> Optional<T> removeAttachment(AttachmentKey<T> key, State state) {
+                Preconditions.checkNotNull(key, "key cannot be null");
+
                 if (state == State.Connection) {
-                    if (value == null) {
-                        return connectionState.remove(key);
-                    }
-                    return connectionState.put(key, value);
+                    return key.convert(connectionState.remove(key));
                 } else {
-                    if (value == null) {
-                        return sstate.remove(key);
-                    }
-                    return sstate.put(key, value);
+                    return key.convert(sessionState.remove(key));
                 }
             }
 
             @Override
-            public Object getAttachment(String key, State state) {
+            public <T> Optional<T> getAttachment(AttachmentKey<T> key, State state) {
                 if (state == State.Connection) {
-                    return connectionState.get(key);
+                    return key.convert(connectionState.get(key));
                 } else {
-                    return sstate.get(key);
+                    return key.convert(sessionState.get(key));
                 }
             }
         };
diff --git a/upgrade-instructions.md b/upgrade-instructions.md
index aa2ade8..0853760 100644
--- a/upgrade-instructions.md
+++ b/upgrade-instructions.md
@@ -30,7 +30,25 @@ Change list:
  - [UidValidity and maildir](#uid-validity-and-maildir)
  - [UidValidity and JPA or Cassandra](#uid-validity-and-jpa-or-cassandra)
  - [Differentiation between domain alias and domain mapping](#differentiation-between-domain-alias-and-domain-mapping)
+ - [ProtocolSession storng typing](#protocolsession-storng-typing)
  
+### ProtocolSession storng typing
+
+Date 19/03/2020
+
+SHA-1 XXX
+
+JIRA: https://issues.apache.org/jira/browse/JAMES-3119
+
+`ProtocolSession` have been reworked in order to increase type strengh
+and reduce errors.
+
+Now `setAttachment` and `getAttachment` are expecting an `AttachmentKey` as key
+and return an `Optional` instead of a `null`-able value.
+
+Moreover `setAttachment` do not allow `null` values and `removeAttachment`
+should be use now to remove elements.
+
 ### Differentiation between domain alias and domain mapping
 
 Date 10/03/2020


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org