james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rouaz...@apache.org
Subject [james-project] 02/07: JAMES-2578 Fix warning using Mailet new API
Date Fri, 15 Feb 2019 13:30:37 GMT
This is an automated email from the ASF dual-hosted git repository.

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

commit 429e9b15939d452338b4388760f94d0ca1f14a3e
Author: Gautier DI FOLCO <gdifolco@linagora.com>
AuthorDate: Tue Feb 5 15:48:29 2019 +0100

    JAMES-2578 Fix warning using Mailet new API
---
 .../api/src/main/java/org/apache/mailet/Mail.java  |  12 +-
 .../james/transport/mailets/AbstractSign.java      |  12 +-
 .../transport/mailets/ICALToJsonAttributeTest.java |   5 +-
 .../transport/mailets/ICalendarParserTest.java     |  15 ++-
 .../transport/mailets/AmqpForwardAttribute.java    |  61 +++++----
 .../james/transport/mailets/StripAttachment.java   |  44 ++++---
 .../james/transport/matchers/HasException.java     |  17 ++-
 .../transport/matchers/SMTPAuthSuccessful.java     |  10 +-
 .../james/transport/matchers/SMTPAuthUserIs.java   |  12 +-
 .../mailets/AmqpForwardAttributeTest.java          |  23 ++--
 .../transport/mailets/ContactExtractorTest.java    |  35 ++++--
 .../mailets/MailAttributesToMimeHeadersTest.java   |  47 +++----
 .../transport/mailets/MimeDecodingMailetTest.java  |  32 +++--
 .../transport/mailets/SetMailAttributeTest.java    |   9 +-
 .../transport/mailets/StripAttachmentTest.java     | 136 +++++++++++++--------
 .../matchers/AbstractHasMailAttributeTest.java     |  24 ++--
 .../james/transport/matchers/HasExceptionTest.java |  16 ++-
 .../transport/matchers/HasMailAttributeTest.java   |   2 +-
 .../HasMailAttributeWithValueRegexTest.java        |   2 +-
 .../matchers/HasMailAttributeWithValueTest.java    |   6 +-
 .../transport/matchers/SMTPAuthSuccessfulTest.java |   4 +-
 .../transport/matchers/SMTPAuthUserIsTest.java     |   7 +-
 .../james/transport/mailets/SpamAssassinTest.java  |  20 +--
 .../james/mailetcontainer/impl/ProcessorUtil.java  |   4 +-
 .../lib/AbstractStateMailetProcessorTest.java      |   3 +-
 .../james/transport/mailets/RemoteDelivery.java    |   2 +-
 .../james/transport/mailets/SpamAssassin.java      |   7 +-
 .../james/transport/mailets/WithPriority.java      |  15 ++-
 .../mailets/managesieve/ManageSieveMailet.java     |   2 +-
 .../mailets/remote/delivery/DeliveryRunnable.java  |   2 +-
 .../james/transport/matchers/IsMarkedAsSpam.java   |   2 +-
 .../james/transport/mailets/SpamAssassinTest.java  |  10 +-
 .../james/transport/mailets/WithPriorityTest.java  |  13 +-
 .../managesieve/ManageSieveMailetTestCase.java     |  12 +-
 .../remote/delivery/RemoteDeliveryTest.java        |   2 +-
 .../james/transport/matchers/dlp/DlpTest.java      |   9 +-
 .../mailrepository/MailRepositoryContract.java     |  10 +-
 .../org/apache/james/jmap/mailet/SentByJmap.java   |  10 +-
 .../org/apache/james/jmap/send/MailMetadata.java   |   5 +-
 .../java/org/apache/james/jmap/send/MailSpool.java |   6 +-
 .../james/jmap/send/PostDequeueDecorator.java      |  39 ++++--
 .../apache/james/jmap/mailet/SentByJmapTest.java   |   6 +-
 .../jmap/mailet/filter/JMAPFilteringExtension.java |   2 +-
 .../jmap/mailet/filter/JMAPFilteringFixture.java   |   4 +-
 .../jmap/mailet/filter/JMAPFilteringTest.java      |  70 ++++++-----
 .../org/apache/james/jmap/send/MailSpoolTest.java  |   6 +-
 .../james/jmap/send/PostDequeueDecoratorTest.java  |  43 ++++---
 .../AddDefaultAttributesMessageHook.java           |   4 +-
 .../james/smtpserver/MailPriorityHandler.java      |   4 +-
 .../smtpserver/fastfail/SpamAssassinHandler.java   |   4 +-
 .../james/smtpserver/SpamAssassinHandlerTest.java  |  21 ++--
 .../james/queue/api/MailPrioritySupport.java       |  23 ++--
 .../api/DelayedPriorityMailQueueContract.java      |   8 +-
 .../apache/james/queue/api/MailQueueContract.java  |  24 ++--
 .../james/queue/api/PriorityMailQueueContract.java |  44 ++++---
 .../api/PriorityManageableMailQueueContract.java   |  26 ++--
 .../org/apache/james/queue/jms/JMSMailQueue.java   |   8 +-
 third-party/spamassassin/pom.xml                   |   4 +
 .../james/spamassassin/SpamAssassinResult.java     |  34 +++---
 .../spamassassin/SpamAssassinInvokerTest.java      |  12 +-
 .../james/spamassassin/SpamAssassinResultTest.java |  20 +--
 61 files changed, 634 insertions(+), 437 deletions(-)

diff --git a/mailet/api/src/main/java/org/apache/mailet/Mail.java b/mailet/api/src/main/java/org/apache/mailet/Mail.java
index afe75f8..34b4e19 100644
--- a/mailet/api/src/main/java/org/apache/mailet/Mail.java
+++ b/mailet/api/src/main/java/org/apache/mailet/Mail.java
@@ -82,9 +82,17 @@ public interface Mail extends Serializable, Cloneable {
     String DEFAULT = "root";
     String ERROR = "error";
     String TRANSPORT = "transport";
-    String SMTP_AUTH_USER_ATTRIBUTE_NAME = "org.apache.james.SMTPAuthUser";
     String SENT_BY_MAILET = "org.apache.james.SentByMailet";
-    String MAILET_ERROR_ATTRIBUTE_NAME = "org.apache.james.MailetError";
+
+    AttributeName SMTP_AUTH_USER = AttributeName.of("org.apache.james.SMTPAuthUser");
+    AttributeName MAILET_ERROR = AttributeName.of("org.apache.james.MailetError");
+
+    @Deprecated
+    String SMTP_AUTH_USER_ATTRIBUTE_NAME = SMTP_AUTH_USER.asString();
+
+    @Deprecated
+    String MAILET_ERROR_ATTRIBUTE_NAME = MAILET_ERROR.asString();
+
     /**
      * Returns the name of this message.
      * 
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 461250d..42bd5f2 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
@@ -24,6 +24,7 @@ package org.apache.james.transport.mailets;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.util.Enumeration;
+import java.util.Optional;
 
 import javax.inject.Inject;
 import javax.mail.MessagingException;
@@ -39,6 +40,7 @@ import org.apache.james.transport.KeyHolder;
 import org.apache.james.transport.SMIMEAttributeNames;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMailet;
 import org.apache.mailet.base.RFC2822Headers;
@@ -561,14 +563,16 @@ public abstract class AbstractSign extends GenericMailet {
         }
 
         MailAddress reversePath = mail.getMaybeSender().get();
-        
-        String authUser = (String) mail.getAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME);
+
+        Optional<String> fetchedAuthUser = AttributeUtils.getValueAndCastFromMail(mail, Mail.SMTP_AUTH_USER, String.class);
         // was the sender user SMTP authorized?
-        if (authUser == null) {
+        if (!fetchedAuthUser.isPresent()) {
             LOGGER.info("Can not sign mail for sender <{}> as he is not a SMTP authenticated user", mail.getMaybeSender().asString());
             return false;
         }
-        
+
+        String authUser = fetchedAuthUser.get();
+
         // The sender is the postmaster?
         if (Objects.equal(getMailetContext().getPostmaster(), reversePath)) {
             // should not sign postmaster sent messages?
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
index 685497c..a95b797 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
@@ -26,7 +26,6 @@ import java.io.ByteArrayInputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
 import java.util.stream.Collectors;
 
 import javax.mail.MessagingException;
@@ -51,8 +50,8 @@ import net.fortuna.ical4j.data.CalendarBuilder;
 import net.fortuna.ical4j.model.Calendar;
 
 public class ICALToJsonAttributeTest {
-    public static final MailAddress SENDER = MailAddressFixture.ANY_AT_JAMES;
-    public static final Class<Map<String, byte[]>> MAP_STRING_BYTES_CLASS = (Class<Map<String, byte[]>>) (Object) Map.class;
+    private static final MailAddress SENDER = MailAddressFixture.ANY_AT_JAMES;
+    private static final Class<Map<String, byte[]>> MAP_STRING_BYTES_CLASS = (Class<Map<String, byte[]>>) (Object) Map.class;
 
     @Rule
     public ExpectedException expectedException = ExpectedException.none();
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
index 8f15ddb..2c8cb0e 100644
--- a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICalendarParserTest.java
@@ -56,6 +56,7 @@ public class ICalendarParserTest {
         "END:VCALENDAR";
 
     private static final String WRONG_ICAL_VALUE = "anyValue";
+    public static final Class<Map<String, Calendar>> MAP_STRING_CALENDAR_CLASS = (Class<Map<String, Calendar>>) (Object) Map.class;
 
     @Rule
     public ExpectedException expectedException = ExpectedException.none();
@@ -224,11 +225,13 @@ public class ICalendarParserTest {
 
         mailet.service(mail);
 
-        Map<String, Calendar> expectedCalendars = (Map<String, Calendar>)mail.getAttribute(DESTINATION_CUSTOM_ATTRIBUTE);
+        Optional<Map<String, Calendar>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, MAP_STRING_CALENDAR_CLASS);
         Map.Entry<String, Calendar> expectedCalendar = Maps.immutableEntry("key2", new Calendar());
 
-        assertThat(expectedCalendars).hasSize(1)
-            .containsExactly(expectedCalendar);
+        assertThat(expectedCalendars).hasValueSatisfying(calendars ->
+            assertThat(calendars)
+                .hasSize(1)
+                .containsExactly(expectedCalendar));
     }
 
     @Test
@@ -256,7 +259,9 @@ public class ICalendarParserTest {
 
         mailet.service(mail);
 
-        Map<String, Calendar> expectedCalendars = (Map<String, Calendar>)mail.getAttribute(DESTINATION_CUSTOM_ATTRIBUTE);
-        assertThat(expectedCalendars).hasSize(1);
+        Optional<Map<String, Calendar>> expectedCalendars = AttributeUtils.getValueAndCastFromMail(mail, DESTINATION_CUSTOM_ATTRIBUTE_NAME, MAP_STRING_CALENDAR_CLASS);
+        assertThat(expectedCalendars).hasValueSatisfying(calendars ->
+                assertThat(calendars)
+                        .hasSize(1));
     }
 }
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/AmqpForwardAttribute.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/AmqpForwardAttribute.java
index 750adc6..671dad1 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/mailets/AmqpForwardAttribute.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/mailets/AmqpForwardAttribute.java
@@ -20,13 +20,16 @@
 package org.apache.james.transport.mailets;
 
 import java.io.IOException;
-import java.io.Serializable;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Stream;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.GenericMailet;
@@ -69,7 +72,7 @@ public class AmqpForwardAttribute extends GenericMailet {
     public static final String ROUTING_KEY_DEFAULT_VALUE = "";
 
     private String exchange;
-    private String attribute;
+    private AttributeName attribute;
     private ConnectionFactory connectionFactory;
     @VisibleForTesting String routingKey;
 
@@ -86,11 +89,12 @@ public class AmqpForwardAttribute extends GenericMailet {
                     + " parameter was provided.");
         }
         routingKey = getInitParameter(ROUTING_KEY_PARAMETER_NAME, ROUTING_KEY_DEFAULT_VALUE);
-        attribute = getInitParameter(ATTRIBUTE_PARAMETER_NAME);
-        if (Strings.isNullOrEmpty(attribute)) {
+        String rawAttribute = getInitParameter(ATTRIBUTE_PARAMETER_NAME);
+        if (Strings.isNullOrEmpty(rawAttribute)) {
             throw new MailetException("No value for " + ATTRIBUTE_PARAMETER_NAME
                     + " parameter was provided.");
         }
+        attribute = AttributeName.of(rawAttribute);
         connectionFactory = new ConnectionFactory();
         try {
             connectionFactory.setUri(uri);
@@ -106,12 +110,34 @@ public class AmqpForwardAttribute extends GenericMailet {
 
     @Override
     public void service(Mail mail) throws MailetException {
-        if (mail.getAttribute(attribute) == null) {
-            return;
+        mail.getAttribute(attribute)
+            .map(Throwing.function(this::getAttributeContent).sneakyThrow())
+            .ifPresent(this::sendContent);
+    }
+
+    private Stream<byte[]> getAttributeContent(Attribute attribute) throws MailetException {
+        return extractAttributeValueContent(attribute.getValue().value())
+                .orElseThrow(() -> new MailetException("Invalid attribute found into attribute "
+                    + this.attribute.asString() + "class Map or List or String expected but "
+                    + attribute.toString() + " found."));
+    }
+
+    private Optional<Stream<byte[]>> extractAttributeValueContent(Object attributeContent) {
+        if (attributeContent instanceof Map) {
+            return Optional.of(((Map<String, byte[]>) attributeContent).values().stream());
         }
-        Stream<byte[]> content = getAttributeContent(mail);
+        if (attributeContent instanceof List) {
+            return Optional.of(((List<AttributeValue<byte[]>>) attributeContent).stream().map(AttributeValue::value));
+        }
+        if (attributeContent instanceof String) {
+            return Optional.of(Stream.of(((String) attributeContent).getBytes(StandardCharsets.UTF_8)));
+        }
+        return Optional.empty();
+    }
+
+    private void sendContent(Stream<byte[]> content) {
         try {
-            sendContent(content);
+            trySendContent(content);
         } catch (IOException e) {
             LOGGER.error("IOException while writing to AMQP: {}", e.getMessage(), e);
         } catch (TimeoutException e) {
@@ -121,24 +147,7 @@ public class AmqpForwardAttribute extends GenericMailet {
         }
     }
 
-    @SuppressWarnings("unchecked")
-    private Stream<byte[]> getAttributeContent(Mail mail) throws MailetException {
-        Serializable attributeContent = mail.getAttribute(attribute);
-        if (attributeContent instanceof Map) {
-            return ((Map<String, byte[]>) attributeContent).values().stream();
-        }
-        if (attributeContent instanceof List) {
-            return ((List<byte[]>) attributeContent).stream();
-        }
-        if (attributeContent instanceof String) {
-            return Stream.of(((String) attributeContent).getBytes(StandardCharsets.UTF_8));
-        }
-        throw new MailetException("Invalid attribute found into attribute "
-                + attribute + "class Map or List or String expected but "
-                + attributeContent.getClass() + " found.");
-    }
-
-    private void sendContent(Stream<byte[]> content) throws IOException, TimeoutException {
+    private void trySendContent(Stream<byte[]> content) throws IOException, TimeoutException {
         Connection connection = null;
         Channel channel = null;
         try {
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/mailets/StripAttachment.java b/mailet/standard/src/main/java/org/apache/james/transport/mailets/StripAttachment.java
index c77f935..45d23ae 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/mailets/StripAttachment.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/mailets/StripAttachment.java
@@ -33,7 +33,9 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.UUID;
+import java.util.function.Function;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import javax.mail.BodyPart;
 import javax.mail.Message;
@@ -48,6 +50,10 @@ import org.apache.commons.io.IOUtils;
 import org.apache.james.javax.MultipartUtil;
 import org.apache.james.mime4j.codec.DecodeMonitor;
 import org.apache.james.mime4j.codec.DecoderUtil;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeUtils;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.GenericMailet;
@@ -86,6 +92,8 @@ import com.google.common.collect.ImmutableList;
 public class StripAttachment extends GenericMailet {
     private static final Logger LOGGER = LoggerFactory.getLogger(StripAttachment.class);
 
+    @SuppressWarnings("unchecked")
+    private static final Class<List<AttributeValue<String>>> LIST_OF_STRINGS = (Class<List<AttributeValue<String>>>)(Object) List.class;
     private static final String MULTIPART_MIME_TYPE = "multipart/*";
     public static final String PATTERN_PARAMETER_NAME = "pattern";
     public static final String NOTPATTERN_PARAMETER_NAME = "notpattern";
@@ -100,8 +108,8 @@ public class StripAttachment extends GenericMailet {
     public static final String REMOVE_NONE = "no";
     public static final String REMOVE_ALL = "all";
     public static final String REMOVE_MATCHED = "matched";
-    public static final String REMOVED_ATTACHMENTS_ATTRIBUTE_KEY = "org.apache.james.mailet.standard.mailets.StripAttachment.removed";
-    public static final String SAVED_ATTACHMENTS_ATTRIBUTE_KEY = "org.apache.james.mailet.standard.mailets.StripAttachment.saved";
+    public static final AttributeName REMOVED_ATTACHMENTS = AttributeName.of("org.apache.james.mailet.standard.mailets.StripAttachment.removed");
+    public static final AttributeName SAVED_ATTACHMENTS = AttributeName.of("org.apache.james.mailet.standard.mailets.StripAttachment.saved");
 
     public static final boolean DECODE_FILENAME_DEFAULT_VALUE = false;
 
@@ -314,7 +322,7 @@ public class StripAttachment extends GenericMailet {
                 shouldRemove = true;
             }
         }
-        storeFileNameAsAttribute(mail, fileName, shouldRemove);
+        storeFileNameAsAttribute(mail, AttributeValue.of(fileName), shouldRemove);
         return shouldRemove;
     }
 
@@ -324,21 +332,23 @@ public class StripAttachment extends GenericMailet {
 
     private void storeBodyPartAsFile(BodyPart bodyPart, Mail mail, String fileName) throws Exception {
         if (directoryName != null) {
-            Optional<String> filename = saveAttachmentToFile(bodyPart, Optional.of(fileName));
-            if (filename.isPresent()) {
-                addFilenameToAttribute(mail, filename.get(), SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-            }
+            saveAttachmentToFile(bodyPart, Optional.of(fileName)).ifPresent(filename ->
+                    addFilenameToAttribute(mail, AttributeValue.of(filename), SAVED_ATTACHMENTS)
+            );
         }
     }
 
-    private void addFilenameToAttribute(Mail mail, String filename, String attributeName) {
-        @SuppressWarnings("unchecked")
-        List<String> attributeValues = (List<String>) mail.getAttribute(attributeName);
-        if (attributeValues == null) {
-            attributeValues = new ArrayList<>();
-            mail.setAttribute(attributeName, (Serializable) attributeValues);
-        }
-        attributeValues.add(filename);
+    private void addFilenameToAttribute(Mail mail, AttributeValue<String> attributeValue, AttributeName attributeName) {
+        Function<List<AttributeValue<String>>, List<AttributeValue<?>>> typeWeakner = values ->
+                values.stream().map(value -> (AttributeValue<?>) value).collect(Collectors.toList());
+
+        ImmutableList.Builder<AttributeValue<?>> attributeValues = ImmutableList.<AttributeValue<?>>builder()
+                .addAll(AttributeUtils
+                    .getValueAndCastFromMail(mail, attributeName, LIST_OF_STRINGS)
+                    .map(typeWeakner)
+                    .orElse(new ArrayList<>()));
+        attributeValues.add(attributeValue);
+        mail.setAttribute(new Attribute(attributeName, AttributeValue.of(attributeValues.build())));
     }
 
     private void storeBodyPartAsMailAttribute(BodyPart bodyPart, Mail mail, String fileName) throws IOException, MessagingException {
@@ -359,9 +369,9 @@ public class StripAttachment extends GenericMailet {
         fileNamesToPartContent.put(fileName, byteArrayOutputStream.toByteArray());
     }
 
-    private void storeFileNameAsAttribute(Mail mail, String fileName, boolean hasToBeStored) {
+    private void storeFileNameAsAttribute(Mail mail, AttributeValue<String> fileName, boolean hasToBeStored) {
         if (hasToBeStored) {
-            addFilenameToAttribute(mail, fileName, REMOVED_ATTACHMENTS_ATTRIBUTE_KEY);
+            addFilenameToAttribute(mail, fileName, REMOVED_ATTACHMENTS);
         }
     }
 
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/matchers/HasException.java b/mailet/standard/src/main/java/org/apache/james/transport/matchers/HasException.java
index 4fc5183..de73946 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/matchers/HasException.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/matchers/HasException.java
@@ -20,10 +20,13 @@
 package org.apache.james.transport.matchers;
 
 import java.util.Collection;
+import java.util.Optional;
 
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMatcher;
 
@@ -67,13 +70,15 @@ public class HasException extends GenericMatcher {
      */
     @Override
     public Collection<MailAddress> match(Mail mail) throws MessagingException {
-        Object exceptionValue = mail.getAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME);
+        Optional<Attribute> exceptionValue = mail.getAttribute(Mail.MAILET_ERROR);
 
-        if (exceptionValue != null && exceptionClass.isAssignableFrom(exceptionValue.getClass())) {
-            return mail.getRecipients();
-        } else {
-            return ImmutableList.of();
-        }
+        return exceptionValue
+            .map(Attribute::getValue)
+            .map(AttributeValue::value)
+            .map(Object::getClass)
+            .filter(exceptionClass::isAssignableFrom)
+            .map(ignored -> mail.getRecipients())
+            .orElse(ImmutableList.of());
     }
 
     @Override
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthSuccessful.java b/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthSuccessful.java
index 2ef9a43..9e23a4e 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthSuccessful.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthSuccessful.java
@@ -47,11 +47,9 @@ public class SMTPAuthSuccessful extends GenericMatcher {
 
     @Override
     public Collection<MailAddress> match(Mail mail) {
-        String authUser = (String) mail.getAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME);
-        if (authUser != null) {
-            return mail.getRecipients();
-        } else {
-            return ImmutableList.of();
-        }
+        return mail
+            .getAttribute(Mail.SMTP_AUTH_USER)
+            .map(ignored -> mail.getRecipients())
+            .orElse(ImmutableList.of());
     }
 }
diff --git a/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthUserIs.java b/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthUserIs.java
index 3e2284b..89c00f1 100644
--- a/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthUserIs.java
+++ b/mailet/standard/src/main/java/org/apache/james/transport/matchers/SMTPAuthUserIs.java
@@ -25,6 +25,7 @@ import java.util.Collection;
 import java.util.StringTokenizer;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMatcher;
 
@@ -57,11 +58,10 @@ public class SMTPAuthUserIs extends GenericMatcher {
 
     @Override
     public Collection<MailAddress> match(Mail mail) {
-        String authUser = (String) mail.getAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME);
-        if (authUser != null && users.contains(authUser)) {
-            return mail.getRecipients();
-        } else {
-            return null;
-        }
+        return AttributeUtils
+            .getValueAndCastFromMail(mail, Mail.SMTP_AUTH_USER, String.class)
+            .filter(users::contains)
+            .map(ignored -> mail.getRecipients())
+            .orElse(null);
     }
 }
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/AmqpForwardAttributeTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/AmqpForwardAttributeTest.java
index 6b959cf..c490b0f 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/AmqpForwardAttributeTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/AmqpForwardAttributeTest.java
@@ -29,10 +29,14 @@ import static org.mockito.Mockito.when;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.util.Optional;
 import java.util.concurrent.TimeoutException;
 
 import javax.mail.MessagingException;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetContext;
 import org.apache.mailet.MailetException;
@@ -56,12 +60,13 @@ import com.rabbitmq.client.ShutdownSignalException;
 
 class AmqpForwardAttributeTest {
 
-    private static final String MAIL_ATTRIBUTE = "ampq.attachments";
+    private static final AttributeName MAIL_ATTRIBUTE = AttributeName.of("ampq.attachments");
     private static final String EXCHANGE_NAME = "exchangeName";
     private static final String ROUTING_KEY = "routingKey";
     private static final String AMQP_URI = "amqp://host";
     private static final byte[] ATTACHMENT_CONTENT = "Attachment content".getBytes(StandardCharsets.UTF_8);
-    private static final ImmutableMap<String, byte[]> ATTRIBUTE_CONTENT = ImmutableMap.of("attachment1.txt", ATTACHMENT_CONTENT);
+    private static final ImmutableMap<String, byte[]> ATTRIBUTE_VALUE = ImmutableMap.of("attachment1.txt", ATTACHMENT_CONTENT);
+    private static final Optional<Attribute> ATTRIBUTE_CONTENT = Optional.of(new Attribute(MAIL_ATTRIBUTE, AttributeValue.ofAny(ATTRIBUTE_VALUE)));
 
     private AmqpForwardAttribute mailet;
     private MailetContext mailetContext;
@@ -80,7 +85,7 @@ class AmqpForwardAttributeTest {
                 .setProperty("uri", AMQP_URI)
                 .setProperty("exchange", EXCHANGE_NAME)
                 .setProperty("routing_key", ROUTING_KEY)
-                .setProperty("attribute", MAIL_ATTRIBUTE)
+                .setProperty("attribute", MAIL_ATTRIBUTE.asString())
                 .build();
     }
 
@@ -124,7 +129,7 @@ class AmqpForwardAttributeTest {
                 .mailetContext(mailetContext)
                 .setProperty("uri", "bad-uri")
                 .setProperty("exchange", EXCHANGE_NAME)
-                .setProperty("attribute", MAIL_ATTRIBUTE)
+                .setProperty("attribute", MAIL_ATTRIBUTE.asString())
                 .build();
         assertThatThrownBy(() -> mailet.init(customMailetConfig))
             .isInstanceOf(MailetException.class);
@@ -142,7 +147,7 @@ class AmqpForwardAttributeTest {
                 .mailetContext(mailetContext)
                 .setProperty("uri", AMQP_URI)
                 .setProperty("exchange", EXCHANGE_NAME)
-                .setProperty("attribute", MAIL_ATTRIBUTE)
+                .setProperty("attribute", MAIL_ATTRIBUTE.asString())
                 .build();
         mailet.init(customMailetConfig);
 
@@ -162,7 +167,7 @@ class AmqpForwardAttributeTest {
         when(connectionFactory.newConnection()).thenReturn(connection);
         mailet.setConnectionFactory(connectionFactory);
         Mail mail = mock(Mail.class);
-        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(null);
+        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(Optional.empty());
 
         mailet.service(mail);
 
@@ -173,7 +178,7 @@ class AmqpForwardAttributeTest {
     public void serviceShouldThrowWhenAttributeContentIsNotAMapAListOrAString() throws MessagingException {
         mailet.init(mailetConfig);
         Mail mail = mock(Mail.class);
-        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(2);
+        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(Optional.of(new Attribute(MAIL_ATTRIBUTE, AttributeValue.of(2))));
 
         assertThatThrownBy(() -> mailet.service(mail))
             .isInstanceOf(MailetException.class);
@@ -246,7 +251,7 @@ class AmqpForwardAttributeTest {
         when(connectionFactory.newConnection()).thenReturn(connection);
         mailet.setConnectionFactory(connectionFactory);
         Mail mail = mock(Mail.class);
-        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(ImmutableList.of(ATTACHMENT_CONTENT));
+        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(Optional.of(new Attribute(MAIL_ATTRIBUTE, AttributeValue.of(ImmutableList.of(AttributeValue.ofSerializable(ATTACHMENT_CONTENT))))));
         BasicProperties expectedProperties = new AMQP.BasicProperties();
 
         mailet.service(mail);
@@ -267,7 +272,7 @@ class AmqpForwardAttributeTest {
         mailet.setConnectionFactory(connectionFactory);
         Mail mail = mock(Mail.class);
         String content = "Attachment content";
-        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(content);
+        when(mail.getAttribute(MAIL_ATTRIBUTE)).thenReturn(Optional.of(new Attribute(MAIL_ATTRIBUTE, AttributeValue.of(content))));
         BasicProperties expectedProperties = new AMQP.BasicProperties();
 
         mailet.service(mail);
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java
index 83b9ddb..fdfe437 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/ContactExtractorTest.java
@@ -30,6 +30,7 @@ import javax.mail.internet.MimeMessage;
 
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.util.MimeMessageUtil;
+import org.apache.mailet.AttributeName;
 import org.apache.mailet.MailetContext;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.test.FakeMail;
@@ -44,7 +45,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 
 public class ContactExtractorTest {
 
-    private static final String ATTRIBUTE = "ExtractedContacts";
+    private static final AttributeName ATTRIBUTE_NAME = AttributeName.of("ExtractedContacts");
     private static final String SENDER = "sender@james.org";
     private static final String TO = "to@james.org";
 
@@ -60,7 +61,7 @@ public class ContactExtractorTest {
         mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .mailetContext(mailetContext)
-                .setProperty(ContactExtractor.Configuration.ATTRIBUTE, ATTRIBUTE)
+                .setProperty(ContactExtractor.Configuration.ATTRIBUTE, ATTRIBUTE_NAME.asString())
                 .build();
     }
 
@@ -119,7 +120,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"" + TO + "\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+            assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -138,7 +140,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"To <" + TO + ">\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -157,7 +160,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"Benoît TELLIER <tellier@linagora.com>\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -177,7 +181,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"\\\"recip >> Frédéric RECIPIENT\\\" <frecipient@example.com>\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -197,7 +202,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"User 1 <user1@example.com>\", \"\\\"recip >> Frédéric RECIPIENT\\\" <frecipient@example.com>\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -217,7 +223,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"\\\"User, the first one\\\" <user1@example.com>\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -236,7 +243,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"To <" + TO + ">\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -255,7 +263,8 @@ public class ContactExtractorTest {
         String expectedMessage = "{\"userEmail\" : \"" + SENDER + "\", \"emails\" : [ \"To <" + TO + ">\" ]}";
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE).toString()).isEqualTo(expectedMessage);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME)).hasValueSatisfying(json ->
+                assertThatJson(json.getValue().value().toString()).isEqualTo(expectedMessage));
     }
 
     @Test
@@ -271,7 +280,8 @@ public class ContactExtractorTest {
 
         mailet.service(mail);
 
-        assertThatJson(mail.getAttribute(ATTRIBUTE)).isEqualTo(null);
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME))
+            .isEmpty();
     }
 
     @Test
@@ -287,7 +297,8 @@ public class ContactExtractorTest {
 
         mailet.service(mail);
 
-        assertThat(mail.getAttribute(ATTRIBUTE)).isNull();
+        assertThat(mail.getAttribute(ATTRIBUTE_NAME))
+            .isEmpty();
     }
 
     @Test
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/MailAttributesToMimeHeadersTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/MailAttributesToMimeHeadersTest.java
index 3b9e845..deef219 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/MailAttributesToMimeHeadersTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/MailAttributesToMimeHeadersTest.java
@@ -25,6 +25,9 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.builder.MimeMessageBuilder;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mailet;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailetConfig;
@@ -39,11 +42,13 @@ class MailAttributesToMimeHeadersTest {
     private static final String HEADER_NAME1 = "JUNIT";
     private static final String HEADER_NAME2 = "JUNIT2";
 
-    private static final String MAIL_ATTRIBUTE_VALUE1 = "test1";
-    private static final String MAIL_ATTRIBUTE_VALUE2 = "test2";
+    private static final AttributeName MAIL_ATTRIBUTE_NAME1 = AttributeName.of("org.apache.james.test");
+    private static final AttributeValue<String> MAIL_ATTRIBUTE_VALUE1 = AttributeValue.of("test1");
+    private static final Attribute MAIL_ATTRIBUTE1 = new Attribute(MAIL_ATTRIBUTE_NAME1, MAIL_ATTRIBUTE_VALUE1);
 
-    private static final String MAIL_ATTRIBUTE_NAME1 = "org.apache.james.test";
-    private static final String MAIL_ATTRIBUTE_NAME2 = "org.apache.james.test2";
+    private static final AttributeName MAIL_ATTRIBUTE_NAME2 = AttributeName.of("org.apache.james.test2");
+    private static final AttributeValue<String> MAIL_ATTRIBUTE_VALUE2 = AttributeValue.of("test2");
+    private static final Attribute MAIL_ATTRIBUTE2 = new Attribute(MAIL_ATTRIBUTE_NAME2, MAIL_ATTRIBUTE_VALUE2);
 
     @BeforeEach
     void setup() {
@@ -76,16 +81,16 @@ class MailAttributesToMimeHeadersTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
             .mailetName("Test")
             .setProperty("simplemapping",
-                MAIL_ATTRIBUTE_NAME1 + "; " + HEADER_NAME1 +
-                    "," + MAIL_ATTRIBUTE_NAME2 + "; " + HEADER_NAME2 +
+                MAIL_ATTRIBUTE_NAME1.asString() + "; " + HEADER_NAME1 +
+                    "," + MAIL_ATTRIBUTE_NAME2.asString() + "; " + HEADER_NAME2 +
                     "," + "another.attribute" + "; " + "Another-Header")
             .build();
 
         mailet.init(mailetConfig);
 
         FakeMail mockedMail = MailUtil.createMockMail2Recipients(MailUtil.createMimeMessage());
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME1, MAIL_ATTRIBUTE_VALUE1);
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME2, MAIL_ATTRIBUTE_VALUE2);
+        mockedMail.setAttribute(MAIL_ATTRIBUTE1);
+        mockedMail.setAttribute(MAIL_ATTRIBUTE2);
 
         mailet.service(mockedMail);
         assertThat(mockedMail.getMessage().getHeader("another.attribute")).isNull();
@@ -96,16 +101,16 @@ class MailAttributesToMimeHeadersTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
             .mailetName("Test")
             .setProperty("simplemapping",
-                MAIL_ATTRIBUTE_NAME1 + "; " + HEADER_NAME1)
+                MAIL_ATTRIBUTE_NAME1.asString() + "; " + HEADER_NAME1)
             .build();
 
         mailet.init(mailetConfig);
 
         FakeMail mockedMail = MailUtil.createMockMail2Recipients(MailUtil.createMimeMessage());
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME1, MAIL_ATTRIBUTE_VALUE1);
+        mockedMail.setAttribute(MAIL_ATTRIBUTE1);
 
         mailet.service(mockedMail);
-        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly(MAIL_ATTRIBUTE_VALUE1);
+        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly(MAIL_ATTRIBUTE_VALUE1.value());
     }
 
     @Test
@@ -113,39 +118,39 @@ class MailAttributesToMimeHeadersTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .setProperty("simplemapping", 
-                        MAIL_ATTRIBUTE_NAME1 + "; " + HEADER_NAME1 +
-                        "," + MAIL_ATTRIBUTE_NAME2 + "; " + HEADER_NAME2 + 
+                        MAIL_ATTRIBUTE_NAME1.asString() + "; " + HEADER_NAME1 +
+                        "," + MAIL_ATTRIBUTE_NAME2.asString() + "; " + HEADER_NAME2 +
                         "," + "another.attribute" + "; " + "Another-Header")
                 .build();
         mailet.init(mailetConfig);
         
         FakeMail mockedMail = MailUtil.createMockMail2Recipients(MailUtil.createMimeMessage());
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME1, MAIL_ATTRIBUTE_VALUE1);
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME2, MAIL_ATTRIBUTE_VALUE2);
-        mockedMail.setAttribute("unmatched.attribute", "value");
+        mockedMail.setAttribute(MAIL_ATTRIBUTE1);
+        mockedMail.setAttribute(MAIL_ATTRIBUTE2);
+        mockedMail.setAttribute(Attribute.convertToAttribute("unmatched.attribute", "value"));
 
         mailet.service(mockedMail);
 
-        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly(MAIL_ATTRIBUTE_VALUE1);
-        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME2)).containsExactly(MAIL_ATTRIBUTE_VALUE2);
+        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly(MAIL_ATTRIBUTE_VALUE1.value());
+        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME2)).containsExactly(MAIL_ATTRIBUTE_VALUE2.value());
     }
 
     @Test
     void shouldAddAttributeIntoHeadersWhenHeaderAlreadyPresent() throws MessagingException {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
-                .setProperty("simplemapping", MAIL_ATTRIBUTE_NAME1 + "; " + HEADER_NAME1)
+                .setProperty("simplemapping", MAIL_ATTRIBUTE_NAME1.asString() + "; " + HEADER_NAME1)
                 .build();
         mailet.init(mailetConfig);
 
         FakeMail mockedMail = MailUtil.createMockMail2Recipients(MimeMessageBuilder.mimeMessageBuilder()
             .addHeader(HEADER_NAME1, "first value")
             .build());
-        mockedMail.setAttribute(MAIL_ATTRIBUTE_NAME1, MAIL_ATTRIBUTE_VALUE1);
+        mockedMail.setAttribute(MAIL_ATTRIBUTE1);
         
         mailet.service(mockedMail);
 
-        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly("first value", MAIL_ATTRIBUTE_VALUE1);
+        assertThat(mockedMail.getMessage().getHeader(HEADER_NAME1)).containsExactly("first value", MAIL_ATTRIBUTE_VALUE1.value());
     }
 
     
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/MimeDecodingMailetTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/MimeDecodingMailetTest.java
index dc62744..685c375 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/MimeDecodingMailetTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/MimeDecodingMailetTest.java
@@ -24,9 +24,14 @@ import static org.mockito.Mockito.mock;
 
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
+import java.util.Optional;
 
 import javax.mail.MessagingException;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeUtils;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.MailetContext;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.test.FakeMail;
@@ -42,7 +47,8 @@ import com.google.common.collect.ImmutableMap;
 
 class MimeDecodingMailetTest {
 
-    private static final String MAIL_ATTRIBUTE = "mime.attachments";
+    private static final AttributeName MAIL_ATTRIBUTE = AttributeName.of("mime.attachments");
+    private static final Class<Map<String, byte[]>> MAP_STRING_BYTES_CLASS = (Class<Map<String, byte[]>>) (Object) Map.class;
 
     private MailetContext mailetContext;
     private MimeDecodingMailet testee;
@@ -82,12 +88,12 @@ class MimeDecodingMailetTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .mailetContext(mailetContext)
-                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE)
+                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE.asString())
                 .build();
         testee.init(mailetConfig);
 
         FakeMail mail = FakeMail.defaultFakeMail();
-        mail.setAttribute(MAIL_ATTRIBUTE, ImmutableList.of());
+        mail.setAttribute(new Attribute(MAIL_ATTRIBUTE, AttributeValue.of(ImmutableList.of())));
 
         testee.service(mail);
     }
@@ -97,12 +103,13 @@ class MimeDecodingMailetTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .mailetContext(mailetContext)
-                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE)
+                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE.asString())
                 .build();
         testee.init(mailetConfig);
 
         FakeMail mail = FakeMail.defaultFakeMail();
-        mail.setAttribute(MAIL_ATTRIBUTE, ImmutableMap.of("1", "2"));
+        AttributeValue<Map<String, AttributeValue<?>>> value = AttributeValue.of(ImmutableMap.of("1", AttributeValue.of("2")));
+        mail.setAttribute(new Attribute(MAIL_ATTRIBUTE, value));
 
         testee.service(mail);
     }
@@ -112,14 +119,14 @@ class MimeDecodingMailetTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .mailetContext(mailetContext)
-                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE)
+                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE.asString())
                 .build();
         testee.init(mailetConfig);
 
         FakeMail mail = FakeMail.defaultFakeMail();
 
         testee.service(mail);
-        assertThat(mail.getAttribute(MAIL_ATTRIBUTE)).isNull();
+        assertThat(mail.getAttribute(MAIL_ATTRIBUTE)).isEmpty();
     }
 
     @Test
@@ -128,7 +135,7 @@ class MimeDecodingMailetTest {
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
                 .mailetContext(mailetContext)
-                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE)
+                .setProperty(MimeDecodingMailet.ATTRIBUTE_PARAMETER_NAME, MAIL_ATTRIBUTE.asString())
                 .build();
         testee.init(mailetConfig);
 
@@ -138,12 +145,15 @@ class MimeDecodingMailetTest {
                 + "Content-Type: application/octet-stream; charset=utf-8\r\n\r\n"
                 + text;
         String expectedKey = "mimePart1";
-        mail.setAttribute(MAIL_ATTRIBUTE, ImmutableMap.of(expectedKey, content.getBytes(StandardCharsets.UTF_8)));
+        AttributeValue<?> value = AttributeValue.ofAny(ImmutableMap.of(expectedKey, content.getBytes(StandardCharsets.UTF_8)));
+        mail.setAttribute(new Attribute(MAIL_ATTRIBUTE, value));
 
         byte[] expectedValue = text.getBytes(StandardCharsets.UTF_8);
         testee.service(mail);
 
-        Map<String, byte[]> processedAttribute = (Map<String, byte[]>) mail.getAttribute(MAIL_ATTRIBUTE);
-        assertThat(processedAttribute).containsExactly(MapEntry.entry(expectedKey, expectedValue));
+        Optional<Map<String, byte[]>> processedAttribute = AttributeUtils.getValueAndCastFromMail(mail, MAIL_ATTRIBUTE, MAP_STRING_BYTES_CLASS);
+        assertThat(processedAttribute).hasValueSatisfying(map ->
+            assertThat(map)
+                .containsExactly(MapEntry.entry(expectedKey, expectedValue)));
     }
 }
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java
index 7edd609..4556744 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/SetMailAttributeTest.java
@@ -85,18 +85,21 @@ class SetMailAttributeTest {
     
     @Test
     void shouldOverwriteAttributeWhenAttributeAlreadyPresent() throws MessagingException {
+        AttributeName name = AttributeName.of("org.apache.james.junit1");
+        Attribute mailAttribute = new Attribute(name, AttributeValue.of("foo"));
+        Attribute replacedAttribute = new Attribute(name, AttributeValue.of("bar"));
         FakeMailetConfig mailetConfig = FakeMailetConfig.builder()
                 .mailetName("Test")
-                .setProperty("org.apache.james.junit1", "bar")
+                .setProperty(name.asString(), (String) replacedAttribute.getValue().value())
                 .build();
         
         mailet.init(mailetConfig);
         
         Mail mail = MailUtil.createMockMail2Recipients(MimeMessageUtil.defaultMimeMessage());
-        mail.setAttribute("org.apache.james.junit1", "foo");
+        mail.setAttribute(mailAttribute);
         
         mailet.service(mail);
 
-        assertThat(mail.getAttribute("org.apache.james.junit1")).isEqualTo("bar");
+        assertThat(mail.getAttribute(name)).contains(replacedAttribute);
     }
 }
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/mailets/StripAttachmentTest.java b/mailet/standard/src/test/java/org/apache/james/transport/mailets/StripAttachmentTest.java
index aefc067..36da780 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/mailets/StripAttachmentTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/mailets/StripAttachmentTest.java
@@ -29,7 +29,6 @@ import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 
@@ -40,22 +39,31 @@ import javax.mail.internet.MimeBodyPart;
 import javax.mail.internet.MimeMessage;
 import javax.mail.internet.MimeMultipart;
 
+import com.github.fge.lambdas.Throwing;
+import com.github.fge.lambdas.consumers.ConsumerChainer;
 import org.apache.commons.io.IOUtils;
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.junit.TemporaryFolderExtension;
 import org.apache.james.junit.TemporaryFolderExtension.TemporaryFolder;
 import org.apache.james.transport.mailets.StripAttachment.OutputFileName;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeUtils;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.Mailet;
 import org.apache.mailet.MailetException;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailetConfig;
+import org.assertj.core.api.Assertions;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 
 @ExtendWith(TemporaryFolderExtension.class)
 class StripAttachmentTest {
 
+    private static Class<Collection<AttributeValue<String>>> COLLECTION_STRING_CLASS = (Class<Collection<AttributeValue<String>>>) (Object) Collection.class;
+    private static Class<Map<String, byte[]>> MAP_STRING_BYTES_CLASS = (Class<Map<String, byte[]>>) (Object) Map.class;
+
     private static final String EXPECTED_ATTACHMENT_CONTENT = "#¤ãàé";
     private static final Optional<String> ABSENT_MIME_TYPE = Optional.empty();
     private static final String CONTENT_TRANSFER_ENCODING_VALUE = "8bit";
@@ -117,14 +125,15 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        Collection<String> savedAttachments = (Collection<String>) mail.getAttribute(StripAttachment.SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(savedAttachments).isNotNull();
-        assertThat(savedAttachments).hasSize(1);
-
-        String attachmentFilename = savedAttachments.iterator().next();
+        Optional<Collection<AttributeValue<String>>> savedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.SAVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(savedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments -> {
+                assertThat(attachments).hasSize(1);
 
-        assertThat(new File(temporaryFolder.getFolderPath() + attachmentFilename)).hasContent(expectedAttachmentContent);
+                String attachmentFilename = attachments.iterator().next().value();
+                assertThat(new File(temporaryFolder.getFolderPath() + attachmentFilename)).hasContent(expectedAttachmentContent);
+            });
     }
 
     @Test
@@ -151,9 +160,11 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        List<String> removedAttachments = (List<String>) mail.getAttribute(StripAttachment.REMOVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(removedAttachments).containsOnly(expectedFileName);
+        Optional<Collection<AttributeValue<String>>> removedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.REMOVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(removedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments ->
+                assertThat(attachments).containsOnly(AttributeValue.of(expectedFileName)));
     }
 
     private MimeMessageBuilder.BodyPartBuilder createAttachmentBodyPart(String body, String fileName, MimeMessageBuilder.Header... headers) {
@@ -188,18 +199,21 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        Collection<String> savedAttachments = (Collection<String>) mail.getAttribute(StripAttachment.SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(savedAttachments).isNotNull();
-        assertThat(savedAttachments).hasSize(2);
+        Optional<Collection<AttributeValue<String>>> savedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.SAVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(savedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments -> {
+                assertThat(attachments).hasSize(2);
 
-        String attachmentFilename = retrieveFilenameStartingWith(savedAttachments, "temp_filname");
-        assertThat(attachmentFilename).isNotNull();
-        assertThat(new File(temporaryFolder.getFolderPath() + attachmentFilename)).hasContent(expectedAttachmentContent);
+                String attachmentFilename = retrieveFilenameStartingWith(attachments, "temp_filname");
+                assertThat(attachmentFilename).isNotNull();
+                assertThat(new File(temporaryFolder.getFolderPath() + attachmentFilename)).hasContent(expectedAttachmentContent);
+            });
     }
 
-    private String retrieveFilenameStartingWith(Collection<String> savedAttachments, String filename) {
+    private String retrieveFilenameStartingWith(Collection<AttributeValue<String>> savedAttachments, String filename) {
         return savedAttachments.stream()
+                .map(AttributeValue::value)
                 .filter(attachmentFilename -> attachmentFilename.startsWith(filename))
                 .findFirst()
                 .get();
@@ -222,16 +236,19 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        Collection<String> savedAttachments = (Collection<String>) mail.getAttribute(StripAttachment.SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(savedAttachments).isNotNull();
-        assertThat(savedAttachments).hasSize(1);
+        Optional<Collection<AttributeValue<String>>> savedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.SAVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(savedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments -> {
+                assertThat(attachments).hasSize(1);
 
-        String name = savedAttachments.iterator().next();
+                String name = attachments.iterator().next().value();
+
+                assertThat(name.startsWith("e_Pubblicita_e_vietata_Milano9052")).isTrue();
+
+                assertThat(new File(temporaryFolder.getFolderPath() + name)).hasContent(expectedAttachmentContent);
+            });
 
-        assertThat(name.startsWith("e_Pubblicita_e_vietata_Milano9052")).isTrue();
-        
-        assertThat(new File(temporaryFolder.getFolderPath() + name)).hasContent(expectedAttachmentContent);
     }
 
     @Test
@@ -260,13 +277,19 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        Map<String, byte[]> saved = (Map<String, byte[]>) mail.getAttribute(customAttribute);
-        assertThat(saved).hasSize(1);
-        assertThat(saved).containsKey(expectedKey);
-        MimeBodyPart savedBodyPart = new MimeBodyPart(new ByteArrayInputStream(saved.get(expectedKey)));
-        String content = IOUtils.toString(savedBodyPart.getInputStream(), StandardCharsets.UTF_8);
-        assertThat(content).isEqualTo(EXPECTED_ATTACHMENT_CONTENT);
+        Optional<Map<String, byte[]>> savedValue = AttributeUtils.getValueAndCastFromMail(mail, AttributeName.of(customAttribute), MAP_STRING_BYTES_CLASS);
+        ConsumerChainer<Map<String, byte[]>> assertValue = Throwing.consumer(saved -> {
+            assertThat(saved)
+                    .hasSize(1)
+                    .containsKeys(expectedKey);
+
+            MimeBodyPart savedBodyPart = new MimeBodyPart(new ByteArrayInputStream(saved.get(expectedKey)));
+            String content = IOUtils.toString(savedBodyPart.getInputStream(), StandardCharsets.UTF_8);
+            assertThat(content).isEqualTo(EXPECTED_ATTACHMENT_CONTENT);
+        });
+        assertThat(savedValue)
+                .isPresent()
+                .hasValueSatisfying(assertValue.sneakyThrow());
     }
 
     @Test
@@ -292,13 +315,19 @@ class StripAttachmentTest {
 
         mailet.service(mail);
 
-        @SuppressWarnings("unchecked")
-        Map<String, byte[]> saved = (Map<String, byte[]>) mail.getAttribute(customAttribute);
-        assertThat(saved).hasSize(1);
-        assertThat(saved).containsKey(expectedKey);
-        MimeBodyPart savedBodyPart = new MimeBodyPart(new ByteArrayInputStream(saved.get(expectedKey)));
-        String content = IOUtils.toString(savedBodyPart.getInputStream(), StandardCharsets.UTF_8);
-        assertThat(content).isEqualTo(EXPECTED_ATTACHMENT_CONTENT);
+        Optional<Map<String, byte[]>> savedValue = AttributeUtils.getValueAndCastFromMail(mail, AttributeName.of(customAttribute), MAP_STRING_BYTES_CLASS);
+        ConsumerChainer<Map<String, byte[]>> assertValue = Throwing.consumer(saved -> {
+            assertThat(saved)
+                    .hasSize(1)
+                    .containsKeys(expectedKey);
+
+            MimeBodyPart savedBodyPart = new MimeBodyPart(new ByteArrayInputStream(saved.get(expectedKey)));
+            String content = IOUtils.toString(savedBodyPart.getInputStream(), StandardCharsets.UTF_8);
+            assertThat(content).isEqualTo(EXPECTED_ATTACHMENT_CONTENT);
+        });
+        assertThat(savedValue)
+            .isPresent()
+            .hasValueSatisfying(assertValue.sneakyThrow());
     }
 
     @Test
@@ -583,9 +612,11 @@ class StripAttachmentTest {
         boolean actual = mailet.processMultipartPartMessage(mimeMessage, mail);
         //Then
         assertThat(actual).isTrue();
-        @SuppressWarnings("unchecked")
-        List<String> values = (List<String>)mail.getAttribute(StripAttachment.SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(values).hasSize(2);
+        Optional<Collection<AttributeValue<String>>> removedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.SAVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(removedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments ->
+                    assertThat(attachments).hasSize(2));
     }
 
     @Test
@@ -618,9 +649,12 @@ class StripAttachmentTest {
         
         //Then
         assertThat(actual).isTrue();
-        @SuppressWarnings("unchecked")
-        Map<String, byte[]> values = (Map<String, byte[]>)mail.getAttribute(customAttribute);
-        assertThat(values).hasSize(2);
+        Optional<Map<String, byte[]>> savedValue = AttributeUtils.getValueAndCastFromMail(mail, AttributeName.of(customAttribute), MAP_STRING_BYTES_CLASS);
+        assertThat(savedValue)
+                .isPresent()
+                .hasValueSatisfying(saved ->
+                    Assertions.assertThat(saved)
+                            .hasSize(2));
     }
 
     @Test
@@ -726,9 +760,11 @@ class StripAttachmentTest {
         boolean actual = mailet.processMultipartPartMessage(mimeMessage, mail);
         //Then
         assertThat(actual).isTrue();
-        @SuppressWarnings("unchecked")
-        List<String> values = (List<String>)mail.getAttribute(StripAttachment.SAVED_ATTACHMENTS_ATTRIBUTE_KEY);
-        assertThat(values).hasSize(1);
+        Optional<Collection<AttributeValue<String>>> removedAttachments = AttributeUtils.getValueAndCastFromMail(mail, StripAttachment.SAVED_ATTACHMENTS, COLLECTION_STRING_CLASS);
+        assertThat(removedAttachments)
+            .isPresent()
+            .hasValueSatisfying(attachments ->
+                    assertThat(attachments).hasSize(1));
     }
 
     @Test
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/AbstractHasMailAttributeTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/AbstractHasMailAttributeTest.java
index 652955a..ecd1692 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/AbstractHasMailAttributeTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/AbstractHasMailAttributeTest.java
@@ -29,6 +29,7 @@ import java.util.Collection;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
 import org.apache.mailet.Matcher;
 import org.apache.mailet.base.GenericMatcher;
 import org.apache.mailet.base.test.FakeMail;
@@ -43,26 +44,16 @@ public abstract class AbstractHasMailAttributeTest {
 
     protected Matcher matcher;
 
-    static final String MAIL_ATTRIBUTE_NAME = "org.apache.james.test.junit";
+    static final Attribute MAIL_ATTRIBUTE = Attribute.convertToAttribute("org.apache.james.test.junit", "true");
+    private Attribute mailAttribute = Attribute.convertToAttribute("org.apache.james", "false");
 
-    static final String MAIL_ATTRIBUTE_VALUE = "true";
-
-    private String mailAttributeName = "org.apache.james";
-
-    private String mailAttributeValue = "false";
-
-    void setMailAttributeName(String mailAttributeName) {
-        this.mailAttributeName = mailAttributeName;
-    }
-
-    void setMailAttributeValue(String mailAttributeValue) {
-        this.mailAttributeValue = mailAttributeValue;
+    void setMailAttribute(Attribute mailAttribute) {
+        this.mailAttribute = mailAttribute;
     }
 
     void setupMockedMail() throws MessagingException {
         mockedMail = MailUtil.createMockMail2Recipients();
-        mockedMail.setAttribute(mailAttributeName,
-                mailAttributeValue);
+        mockedMail.setAttribute(mailAttribute);
     }
 
     void setupMatcher() throws MessagingException {
@@ -90,8 +81,7 @@ public abstract class AbstractHasMailAttributeTest {
     }
 
     protected void init() {
-        setMailAttributeName(MAIL_ATTRIBUTE_NAME);
-        setMailAttributeValue(MAIL_ATTRIBUTE_VALUE);
+        setMailAttribute(MAIL_ATTRIBUTE);
     }
 
     void setupAll() throws MessagingException {
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java
index 3392e65..ff30cd4 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasExceptionTest.java
@@ -23,13 +23,17 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import javax.mail.MessagingException;
+import javax.mail.internet.AddressException;
 import javax.mail.internet.MimeMessage;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.Matcher;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMatcherConfig;
 import org.apache.mailet.base.test.MailUtil;
+
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
@@ -47,7 +51,7 @@ public class HasExceptionTest {
 
     @Test
     public void matchShouldReturnAddressesWhenSpecifiedExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new javax.mail.internet.AddressException());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new AddressException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -61,7 +65,7 @@ public class HasExceptionTest {
 
     @Test
     public void matchShouldReturnAddressesWhenSubclassOfSpecifiedExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new javax.mail.internet.AddressException());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new AddressException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -75,7 +79,7 @@ public class HasExceptionTest {
 
     @Test
     public void matchShouldReturnEmptyWhenOtherExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new java.lang.RuntimeException());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new java.lang.RuntimeException())));
 
         testee.init(FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -87,7 +91,7 @@ public class HasExceptionTest {
 
     @Test
     public void matchShouldReturnEmptyWhenSuperclassOfSpecifiedExceptionHasOccurred() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new javax.mail.MessagingException());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new javax.mail.MessagingException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -113,7 +117,7 @@ public class HasExceptionTest {
 
     @Test
     public void matchShouldReturnEmptyWhenNonExceptionIsAttached() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new java.lang.String());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.of(new java.lang.String())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
@@ -147,7 +151,7 @@ public class HasExceptionTest {
     
     @Test
     public void initShouldRaiseMessagingExceptionWhenClassNameIsNotFullyQualified() throws MessagingException {
-        mockedMail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, new javax.mail.MessagingException());
+        mockedMail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(new javax.mail.MessagingException())));
 
         FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
                 .matcherName("HasException")
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeTest.java
index e3d1c87..82027dd 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeTest.java
@@ -31,7 +31,7 @@ public class HasMailAttributeTest extends AbstractHasMailAttributeTest {
 
     @Override
     protected String getHasMailAttribute() {
-        return MAIL_ATTRIBUTE_NAME;
+        return MAIL_ATTRIBUTE.getName().asString();
     }
 
     @Override
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueRegexTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueRegexTest.java
index a42b126..c8fb3c6 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueRegexTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueRegexTest.java
@@ -43,7 +43,7 @@ public class HasMailAttributeWithValueRegexTest extends AbstractHasMailAttribute
 
     @Override
     protected String getHasMailAttribute() {
-        return MAIL_ATTRIBUTE_NAME + ", " + regex;
+        return MAIL_ATTRIBUTE.getName().asString() + ", " + regex;
     }
 
     @Override
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueTest.java
index 9412d88..af2c7bf 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/HasMailAttributeWithValueTest.java
@@ -27,6 +27,8 @@ import java.util.Collection;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.base.GenericMatcher;
 import org.junit.jupiter.api.Test;
 
@@ -34,7 +36,7 @@ public class HasMailAttributeWithValueTest extends AbstractHasMailAttributeTest
 
     @Override
     protected String getHasMailAttribute() {
-        return MAIL_ATTRIBUTE_NAME + ", " + MAIL_ATTRIBUTE_VALUE;
+        return MAIL_ATTRIBUTE.getName().asString() + ", " + MAIL_ATTRIBUTE.getValue().value();
     }
 
     @Override
@@ -44,7 +46,7 @@ public class HasMailAttributeWithValueTest extends AbstractHasMailAttributeTest
 
     @Test
     void testAttributeIsNotMatchedCauseValue() throws MessagingException {
-        setMailAttributeName(MAIL_ATTRIBUTE_NAME);
+        setMailAttribute(new Attribute(MAIL_ATTRIBUTE.getName(), AttributeValue.of("false")));
         setupMockedMail();
         setupMatcher();
 
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthSuccessfulTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthSuccessfulTest.java
index 7c47bea..7a36347 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthSuccessfulTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthSuccessfulTest.java
@@ -24,6 +24,8 @@ import static org.assertj.core.api.Assertions.assertThat;
 import java.util.Collection;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.FakeMail;
@@ -49,7 +51,7 @@ public class SMTPAuthSuccessfulTest {
         MailAddress recipient = MailAddressFixture.OTHER_AT_JAMES;
         FakeMail fakeMail = FakeMail.builder()
             .recipient(recipient)
-            .attribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, "other")
+            .attribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of("other")))
             .build();
 
         Collection<MailAddress> results =  testee.match(fakeMail);
diff --git a/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthUserIsTest.java b/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthUserIsTest.java
index ef19a41..aff1727 100644
--- a/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthUserIsTest.java
+++ b/mailet/standard/src/test/java/org/apache/james/transport/matchers/SMTPAuthUserIsTest.java
@@ -27,6 +27,8 @@ import java.util.Collection;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMatcher;
 import org.junit.jupiter.api.Test;
@@ -51,8 +53,7 @@ public class SMTPAuthUserIsTest extends AbstractHasMailAttributeTest {
     @Override
     protected void init() {
         super.init();
-        setMailAttributeName(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME);
-        setMailAttributeValue("test@james.apache.org");
+        setMailAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of("test@james.apache.org")));
     }
     
     
@@ -60,7 +61,7 @@ public class SMTPAuthUserIsTest extends AbstractHasMailAttributeTest {
     @Test
     public void testAttributeIsNotMatched() throws MessagingException {
         setupAll();
-        setMailAttributeValue("notmatched@james.apache.org");
+        setMailAttribute(Attribute.convertToAttribute("notmatched@james.apache.org", ""));
 
         Collection<MailAddress> matchedRecipients = matcher.match(mockedMail);
 
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
index aa0cf64..4c144cd 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
@@ -113,8 +113,8 @@ public class SpamAssassinTest {
 
         assertThat(messageReader.readFirstMessageHeaders())
             .contains(
-                SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME,
-                SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME);
+                SpamAssassinResult.FLAG_MAIL.asString(),
+                SpamAssassinResult.STATUS_MAIL.asString());
     }
 
     @Test
@@ -128,8 +128,8 @@ public class SpamAssassinTest {
             .awaitMessage(awaitAtMostOneMinute);
 
         String receivedHeaders = messageReader.readFirstMessageHeaders();
-        assertThat(receivedHeaders).contains(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME + ": YES");
-        assertThat(receivedHeaders).contains(SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME + ": Yes");
+        assertThat(receivedHeaders).contains(SpamAssassinResult.FLAG_MAIL.asString() + ": YES");
+        assertThat(receivedHeaders).contains(SpamAssassinResult.STATUS_MAIL.asString() + ": Yes");
     }
 
     @Test
@@ -143,8 +143,8 @@ public class SpamAssassinTest {
             .awaitMessage(awaitAtMostOneMinute);
 
         String receivedHeaders = messageReader.readFirstMessageHeaders();
-        assertThat(receivedHeaders).contains(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME + ": NO");
-        assertThat(receivedHeaders).contains(SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME + ": No");
+        assertThat(receivedHeaders).contains(SpamAssassinResult.FLAG_MAIL.asString() + ": NO");
+        assertThat(receivedHeaders).contains(SpamAssassinResult.STATUS_MAIL.asString() + ": No");
     }
 
     @Test
@@ -159,8 +159,8 @@ public class SpamAssassinTest {
 
         assertThat(messageReader.readFirstMessageHeaders())
             .contains(
-                SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME,
-                SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME);
+                SpamAssassinResult.FLAG_MAIL.asString(),
+                SpamAssassinResult.STATUS_MAIL.asString());
 
         messageReader.disconnect()
             .connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
@@ -170,8 +170,8 @@ public class SpamAssassinTest {
 
         assertThat(messageReader.readFirstMessageHeaders())
             .contains(
-                SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME,
-                SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME);
+                SpamAssassinResult.FLAG_MAIL.asString(),
+                SpamAssassinResult.STATUS_MAIL.asString());
     }
 
     private FakeMail.Builder mailWithContent(String textContent, String... recipients) throws MessagingException {
diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java
index 3a88963..7f1786b 100644
--- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java
+++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/ProcessorUtil.java
@@ -26,6 +26,8 @@ import java.util.Collection;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetException;
 import org.slf4j.Logger;
@@ -63,7 +65,7 @@ public class ProcessorUtil {
         String errorString = sout.toString();
         mail.setErrorMessage(errorString);
         logger.error(errorString);
-        mail.setAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME, me);
+        mail.setAttribute(new Attribute(Mail.MAILET_ERROR, AttributeValue.ofSerializable(me)));
     }
 
     /**
diff --git a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/lib/AbstractStateMailetProcessorTest.java b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/lib/AbstractStateMailetProcessorTest.java
index fddedaf..b013928 100644
--- a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/lib/AbstractStateMailetProcessorTest.java
+++ b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/lib/AbstractStateMailetProcessorTest.java
@@ -233,7 +233,8 @@ public abstract class AbstractStateMailetProcessorTest {
         processor.service(mail);
 
         // the source mail should have captured the exception which was thrown
-        assertThat(mail.getAttribute(Mail.MAILET_ERROR_ATTRIBUTE_NAME).getClass()).isEqualTo(MessagingException.class);
+        assertThat(mail.getAttribute(Mail.MAILET_ERROR)).hasValueSatisfying(attribute ->
+                assertThat(attribute.getValue().value().getClass()).isEqualTo(MessagingException.class));
         latch.await();
         processor.destroy();
     }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index 4e5d68f..7192edc 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -198,7 +198,7 @@ public class RemoteDelivery extends GenericMailet {
             LOGGER.debug("Remotely delivering mail {}", mail.getName());
         }
         if (configuration.isUsePriority()) {
-            mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY);
+            mail.setAttribute(MailPrioritySupport.HIGH_PRIORITY_ATTRIBUTE);
         }
         if (!mail.getRecipients().isEmpty()) {
             if (configuration.getGatewayServer().isEmpty()) {
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 adda4b7..c69e4ad 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
@@ -33,6 +33,7 @@ import org.apache.james.spamassassin.SpamAssassinResult;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.util.Port;
+import org.apache.mailet.Attribute;
 import org.apache.mailet.Mail;
 import org.apache.mailet.PerRecipientHeaders;
 import org.apache.mailet.base.GenericMailet;
@@ -110,10 +111,10 @@ public class SpamAssassin extends GenericMailet {
         SpamAssassinResult result = sa.scanMail(message, User.fromUsername(usersRepository.getUser(recipient)));
 
         // Add headers per recipient to mail object
-        for (String key : result.getHeadersAsAttribute().keySet()) {
+        for (Attribute attribute : result.getHeadersAsAttributes()) {
             mail.addSpecificHeaderForRecipient(PerRecipientHeaders.Header.builder()
-                    .name(key)
-                    .value(result.getHeadersAsAttribute().get(key))
+                    .name(attribute.getName().asString())
+                    .value((String) attribute.getValue().value())
                     .build(), recipient);
         }
     }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithPriority.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithPriority.java
index 5e5218c..3138f4b 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithPriority.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithPriority.java
@@ -24,6 +24,8 @@ import java.util.Optional;
 import javax.mail.MessagingException;
 
 import org.apache.james.queue.api.MailPrioritySupport;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMailet;
 
@@ -38,7 +40,7 @@ import org.apache.mailet.base.GenericMailet;
  */
 public class WithPriority extends GenericMailet {
 
-    private int priority;
+    private Attribute priority;
 
     @Override
     public String getMailetInfo() {
@@ -47,17 +49,18 @@ public class WithPriority extends GenericMailet {
 
     @Override
     public void init() throws MessagingException {
-        priority = Optional.ofNullable(getInitParameter("priority", null))
-                .map(Integer::valueOf)
-                .orElseThrow(() -> new IllegalArgumentException("'priority' init parameter is compulsory"));
+        Integer priorityRaw = Optional.ofNullable(getInitParameter("priority", null))
+            .map(Integer::valueOf)
+            .orElseThrow(() -> new IllegalArgumentException("'priority' init parameter is compulsory"));
 
-        if (priority < 0 || priority > 9) {
+        if (priorityRaw < 0 || priorityRaw > 9) {
             throw new IllegalArgumentException("Invalid priority: Priority should be from 0 to 9");
         }
+        priority = new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.of(priorityRaw));
     }
 
     @Override
     public void service(Mail mail) throws MessagingException {
-        mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, priority);
+        mail.setAttribute(priority);
     }
 }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java
index 6fb60b7..51285b9 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailet.java
@@ -132,7 +132,7 @@ public class ManageSieveMailet extends GenericMailet implements MessageToCoreToM
 
         // Update the Session for the current mail and execute
         SettableSession session = new SettableSession();
-        if (mail.getAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME) != null) {
+        if (mail.getAttribute(Mail.SMTP_AUTH_USER).isPresent()) {
             session.setState(Session.State.AUTHENTICATED);
         } else {
             session.setState(Session.State.UNAUTHENTICATED);
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
index 53b0420..b5fcebe 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DeliveryRunnable.java
@@ -167,7 +167,7 @@ public class DeliveryRunnable implements Runnable {
 
         if (configuration.isUsePriority()) {
             // Use lowest priority for retries. See JAMES-1311
-            mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY);
+            mail.setAttribute(MailPrioritySupport.LOW_PRIORITY_ATTRIBUTE);
         }
         queue.enQueue(mail, delay, TimeUnit.MILLISECONDS);
     }
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsMarkedAsSpam.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsMarkedAsSpam.java
index bd516f5..1cace4c 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsMarkedAsSpam.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/matchers/IsMarkedAsSpam.java
@@ -73,7 +73,7 @@ public class IsMarkedAsSpam extends GenericMatcher {
     public boolean isMarkedAsSpam(Mail mail, MailAddress recipient) {
         return mail.getPerRecipientSpecificHeaders().getHeadersForRecipient(recipient)
             .stream()
-            .filter(header -> header.getName().equals(SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME))
+            .filter(header -> header.getName().equals(SpamAssassinResult.STATUS_MAIL.asString()))
             .anyMatch(header -> header.getValue().toLowerCase(Locale.US).startsWith(YES));
     }
 
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
index 62565ab..29107f4 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/SpamAssassinTest.java
@@ -170,7 +170,7 @@ public class SpamAssassinTest {
                 .stream()
                 .map(PerRecipientHeaders.Header::getName)
                 .collect(Guavate.toImmutableList()))
-            .contains(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME, SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME);
+            .contains(SpamAssassinResult.FLAG_MAIL.asString(), SpamAssassinResult.STATUS_MAIL.asString());
     }
 
     @Test
@@ -198,12 +198,12 @@ public class SpamAssassinTest {
             .isEqualTo(new PerRecipientHeaders()
                 .addHeaderForRecipient(
                     PerRecipientHeaders.Header.builder()
-                        .name(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)
+                        .name(SpamAssassinResult.FLAG_MAIL.asString())
                         .value("NO"),
                     new MailAddress("user1@exemple.com"))
                 .addHeaderForRecipient(
                     PerRecipientHeaders.Header.builder()
-                        .name(SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME)
+                        .name(SpamAssassinResult.STATUS_MAIL.asString())
                         .value("No, hits=3 required=5"),
                     new MailAddress("user1@exemple.com")));
     }
@@ -233,12 +233,12 @@ public class SpamAssassinTest {
             .isEqualTo(new PerRecipientHeaders()
                 .addHeaderForRecipient(
                     PerRecipientHeaders.Header.builder()
-                        .name(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)
+                        .name(SpamAssassinResult.FLAG_MAIL.asString())
                         .value("YES"),
                     new MailAddress("user1@exemple.com"))
                 .addHeaderForRecipient(
                     PerRecipientHeaders.Header.builder()
-                        .name(SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME)
+                        .name(SpamAssassinResult.STATUS_MAIL.asString())
                         .value("Yes, hits=1000 required=5"),
                     new MailAddress("user1@exemple.com")));
     }
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithPriorityTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithPriorityTest.java
index 5b414b0..4814a66 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithPriorityTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithPriorityTest.java
@@ -23,6 +23,8 @@ import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import org.apache.james.queue.api.MailPrioritySupport;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.MailetConfig;
 import org.apache.mailet.base.test.FakeMail;
@@ -33,6 +35,7 @@ import org.junit.Test;
 
 public class WithPriorityTest {
 
+    private static final Attribute PROPERTY_PRIORITY = new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.of(7));
     private WithPriority mailet;
 
     @Before
@@ -107,29 +110,29 @@ public class WithPriorityTest {
     public void serviceShouldSetMailPriorityWhenNone() throws Exception {
         MailetConfig mockedMailetConfig = FakeMailetConfig.builder()
             .mailetContext(FakeMailContext.defaultContext())
-            .setProperty("priority", "7")
+            .setProperty("priority", PROPERTY_PRIORITY.getValue().value().toString())
             .build();
 
         mailet.init(mockedMailetConfig);
         Mail mail = FakeMail.builder().build();
         mailet.service(mail);
 
-        assertThat(mail.getAttribute(MailPrioritySupport.MAIL_PRIORITY)).isEqualTo(7);
+        assertThat(mail.getAttribute(MailPrioritySupport.MAIL_PRIORITY)).contains(PROPERTY_PRIORITY);
     }
 
     @Test
     public void serviceShouldSetMailPriorityWhenPriorityExists() throws Exception {
         MailetConfig mockedMailetConfig = FakeMailetConfig.builder()
             .mailetContext(FakeMailContext.defaultContext())
-            .setProperty("priority", "7")
+            .setProperty("priority", PROPERTY_PRIORITY.getValue().value().toString())
             .build();
 
         mailet.init(mockedMailetConfig);
         Mail mail = FakeMail.builder()
-                .attribute(MailPrioritySupport.MAIL_PRIORITY, 5)
+                .attribute(new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.of(5)))
                 .build();
         mailet.service(mail);
 
-        assertThat(mail.getAttribute(MailPrioritySupport.MAIL_PRIORITY)).isEqualTo(7);
+        assertThat(mail.getAttribute(MailPrioritySupport.MAIL_PRIORITY)).contains(PROPERTY_PRIORITY);
     }
 }
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailetTestCase.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailetTestCase.java
index 01bc770..7ee74ac 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailetTestCase.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/managesieve/ManageSieveMailetTestCase.java
@@ -49,6 +49,8 @@ import org.apache.james.sieverepository.api.ScriptSummary;
 import org.apache.james.sieverepository.api.SieveRepository;
 import org.apache.james.sieverepository.api.exception.ScriptNotFoundException;
 import org.apache.james.user.api.UsersRepository;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailContext;
@@ -104,7 +106,7 @@ public class ManageSieveMailetTestCase {
         Mail mail = createUnauthenticatedMail(message);
         when(sieveParser.getExtensions()).thenReturn(Lists.newArrayList("a", "b", "c"));
         initializeMailet();
-        mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, "test");
+        mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of("test")));
         mailet.service(mail);
         ensureResponseContains("Re: CAPABILITY", "\"SIEVE\" \"a b c\"",
             "\"IMPLEMENTATION\" \"Apache ManageSieve v1.0\"",
@@ -196,7 +198,7 @@ public class ManageSieveMailetTestCase {
         when(sieveRepository.getScript(USER, SCRIPT_NAME)).thenReturn(new ByteArrayInputStream(SCRIPT_CONTENT.getValue().getBytes(StandardCharsets.UTF_8)));
         MimeMessage message = prepareMimeMessage("GETSCRIPT \"" + SCRIPT_NAME.getValue() + "\"");
         Mail mail = createUnauthenticatedMail(message);
-        mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, USER.asString());
+        mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of(USER.asString())));
         mailet.service(mail);
         ensureResponse("Re: GETSCRIPT \"" + SCRIPT_NAME.getValue() + "\"", "{13}\r\n" + SCRIPT_CONTENT.getValue() + "\r\nOK");
     }
@@ -214,7 +216,7 @@ public class ManageSieveMailetTestCase {
         doThrow(new ScriptNotFoundException()).when(sieveRepository).getScript(USER, SCRIPT_NAME);
         MimeMessage message = prepareMimeMessage("GETSCRIPT \"" + SCRIPT_NAME.getValue() + "\"");
         Mail mail = createUnauthenticatedMail(message);
-        mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, USER.asString());
+        mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of(USER.asString())));
         mailet.service(mail);
         ensureResponse("Re: GETSCRIPT \"" + SCRIPT_NAME.getValue() + "\"", "NO (NONEXISTENT) \"There is no script by that name\"");
     }
@@ -226,7 +228,7 @@ public class ManageSieveMailetTestCase {
         MimeMessage message = prepareMimeMessage("GETSCRIPT");
         Mail mail = createUnauthenticatedMail(message);
 
-        mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, USER.asString());
+        mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of(USER.asString())));
         mailet.service(mail);
         ensureResponse("Re: GETSCRIPT", "NO \"Missing argument: script name\"");
     }
@@ -514,7 +516,7 @@ public class ManageSieveMailetTestCase {
 
     private Mail createAuthentificatedMail(MimeMessage message) throws Exception {
         Mail mail = createUnauthenticatedMail(message);
-        mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, message.getSender().toString());
+        mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of(message.getSender().toString())));
         return mail;
     }
 
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryTest.java
index f7b5bd1..00612ae 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryTest.java
@@ -196,7 +196,7 @@ public class RemoteDeliveryTest {
             .extracting(MailProjection::from)
             .containsOnly(MailProjection.from(FakeMail.builder()
                 .name(MAIL_NAME + RemoteDelivery.NAME_JUNCTION + MailAddressFixture.JAMES_APACHE_ORG)
-                .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY)
+                .attribute(MailPrioritySupport.HIGH_PRIORITY_ATTRIBUTE)
                 .recipient(MailAddressFixture.ANY_AT_JAMES)
                 .build()));
     }
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/dlp/DlpTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/dlp/DlpTest.java
index 88266d6..0070178 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/dlp/DlpTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/matchers/dlp/DlpTest.java
@@ -37,6 +37,9 @@ import org.apache.james.core.Domain;
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.builder.MimeMessageBuilder;
 import org.apache.james.dlp.api.DLPConfigurationItem.Id;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.jupiter.api.Test;
 
@@ -505,12 +508,13 @@ class DlpTest {
 
     @Test
     void matchShouldAttachMatchingRuleNameToMail() throws Exception {
+        String attributeValue = "should match sender";
         Dlp dlp = new Dlp(
             asRulesLoaderFor(
                 JAMES_APACHE_ORG_DOMAIN,
                 DlpDomainRules.builder()
                     .recipientRule(Id.of("should not match recipient"), Pattern.compile(RECIPIENT3.asString()))
-                    .senderRule(Id.of("should match sender"), Pattern.compile(JAMES_APACHE_ORG))
+                    .senderRule(Id.of(attributeValue), Pattern.compile(JAMES_APACHE_ORG))
                     .build()));
 
         FakeMail mail = FakeMail.builder()
@@ -521,7 +525,8 @@ class DlpTest {
 
         dlp.match(mail);
 
-        assertThat(mail.getAttribute("DlpMatchedRule")).isEqualTo("should match sender");
+        AttributeName name = AttributeName.of("DlpMatchedRule");
+        assertThat(mail.getAttribute(name)).contains(new Attribute(name, AttributeValue.of(attributeValue)));
     }
 
 }
\ No newline at end of file
diff --git a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java b/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
index ee74d10..b94e370 100644
--- a/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
+++ b/server/mailrepository/mailrepository-api/src/test/java/org/apache/james/mailrepository/MailRepositoryContract.java
@@ -42,6 +42,8 @@ import org.apache.james.server.core.MailImpl;
 import org.apache.james.util.concurrency.ConcurrentTestRunner;
 import org.apache.james.utils.DiscreteDistribution;
 import org.apache.james.utils.DiscreteDistribution.DistributionEntry;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.PerRecipientHeaders;
 import org.apache.mailet.base.MailAddressFixture;
@@ -58,7 +60,7 @@ import com.google.common.hash.Hashing;
 
 public interface MailRepositoryContract {
 
-    String TEST_ATTRIBUTE = "testAttribute";
+    Attribute TEST_ATTRIBUTE = Attribute.convertToAttribute("testAttribute", "testValue");
     MailKey MAIL_1 = new MailKey("mail1");
     MailKey MAIL_2 = new MailKey("mail2");
     MailKey UNKNOWN_KEY = new MailKey("random");
@@ -74,7 +76,7 @@ public interface MailRepositoryContract {
                 new MailAddress("rec2@domain.com"));
         MailAddress sender = new MailAddress("sender@domain.com");
         MailImpl mail = new MailImpl(key.asString(), sender, recipients, mailContent);
-        mail.setAttribute(TEST_ATTRIBUTE, "testValue");
+        mail.setAttribute(TEST_ATTRIBUTE);
         return mail;
     }
 
@@ -92,7 +94,7 @@ public interface MailRepositoryContract {
             softly.assertThat(actual.getMessageSize()).isEqualTo(expected.getMessageSize());
             softly.assertThat(actual.getName()).isEqualTo(expected.getName());
             softly.assertThat(actual.getState()).isEqualTo(expected.getState());
-            softly.assertThat(actual.getAttribute(TEST_ATTRIBUTE)).isEqualTo(expected.getAttribute(TEST_ATTRIBUTE));
+            softly.assertThat(actual.getAttribute(TEST_ATTRIBUTE.getName())).isEqualTo(expected.getAttribute(TEST_ATTRIBUTE.getName()));
             softly.assertThat(actual.getErrorMessage()).isEqualTo(expected.getErrorMessage());
             softly.assertThat(actual.getRemoteHost()).isEqualTo(expected.getRemoteHost());
             softly.assertThat(actual.getRemoteAddr()).isEqualTo(expected.getRemoteAddr());
@@ -412,7 +414,7 @@ public interface MailRepositoryContract {
         Mail mail = createMail(MAIL_1);
         testee.store(mail);
 
-        mail.setAttribute(TEST_ATTRIBUTE, "newValue");
+        mail.setAttribute(new Attribute(TEST_ATTRIBUTE.getName(), AttributeValue.of("newValue")));
         testee.store(mail);
 
         assertThat(testee.list()).hasSize(1);
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/SentByJmap.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/SentByJmap.java
index be5ba42..1163c5b 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/SentByJmap.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/mailet/SentByJmap.java
@@ -25,6 +25,7 @@ import java.util.Collection;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.jmap.send.MailMetadata;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.GenericMatcher;
 
@@ -33,11 +34,8 @@ import com.google.common.collect.ImmutableList;
 public class SentByJmap extends GenericMatcher {
     @Override
     public Collection<MailAddress> match(Mail mail) {
-        String authUser = (String) mail.getAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE);
-        if (authUser != null) {
-            return mail.getRecipients();
-        } else {
-            return ImmutableList.of();
-        }
+        return AttributeUtils.getAttributeValueFromMail(mail, MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE)
+            .map(ignored -> mail.getRecipients())
+            .orElse(ImmutableList.of());
     }
 }
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java
index 3eebac9..155b58c 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailMetadata.java
@@ -22,12 +22,13 @@ package org.apache.james.jmap.send;
 import java.util.Objects;
 
 import org.apache.james.mailbox.model.MessageId;
+import org.apache.mailet.AttributeName;
 
 import com.google.common.base.Preconditions;
 
 public class MailMetadata {
-    public static final String MAIL_METADATA_MESSAGE_ID_ATTRIBUTE = "org.apache.james.jmap.send.MailMetaData.messageId";
-    public static final String MAIL_METADATA_USERNAME_ATTRIBUTE = "org.apache.james.jmap.send.MailMetaData.username";
+    public static final AttributeName MAIL_METADATA_MESSAGE_ID_ATTRIBUTE = AttributeName.of("org.apache.james.jmap.send.MailMetaData.messageId");
+    public static final AttributeName MAIL_METADATA_USERNAME_ATTRIBUTE = AttributeName.of("org.apache.james.jmap.send.MailMetaData.username");
 
     private final MessageId messageId;
     private final String username;
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java
index db45b4f..b973cee 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/MailSpool.java
@@ -24,6 +24,8 @@ import javax.inject.Inject;
 import org.apache.james.queue.api.MailQueue;
 import org.apache.james.queue.api.MailQueue.MailQueueException;
 import org.apache.james.queue.api.MailQueueFactory;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 
 import com.google.common.annotations.VisibleForTesting;
@@ -38,8 +40,8 @@ public class MailSpool {
     }
 
     public void send(Mail mail, MailMetadata metadata) throws MailQueueException {
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, metadata.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, metadata.getUsername());
+        mail.setAttribute(new Attribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, AttributeValue.of(metadata.getMessageId().serialize())));
+        mail.setAttribute(new Attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, AttributeValue.of(metadata.getUsername())));
         queue.enQueue(mail);
     }
 }
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java
index 4a1df42..44be35b 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/send/PostDequeueDecorator.java
@@ -18,8 +18,8 @@
  ****************************************************************/
 package org.apache.james.jmap.send;
 
-import java.io.Serializable;
 import java.util.List;
+import java.util.Optional;
 
 import javax.mail.Flags;
 import javax.mail.Flags.Flag;
@@ -41,6 +41,8 @@ import org.apache.james.mailbox.model.MessageResult;
 import org.apache.james.queue.api.MailQueue.MailQueueException;
 import org.apache.james.queue.api.MailQueue.MailQueueItem;
 import org.apache.james.queue.api.MailQueueItemDecoratorFactory.MailQueueItemDecorator;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,7 +51,7 @@ import com.google.common.collect.ImmutableList;
 
 public class PostDequeueDecorator extends MailQueueItemDecorator {
     private static final Logger LOG = LoggerFactory.getLogger(PostDequeueDecorator.class);
-    private static final String IS_DELIVERED = "DELIVERED";
+    private static final Attribute IS_DELIVERED = Attribute.convertToAttribute("DELIVERED", "DELIVERED");
 
     private final MailboxManager mailboxManager;
     private final Factory messageIdFactory;
@@ -77,13 +79,14 @@ public class PostDequeueDecorator extends MailQueueItemDecorator {
     public void done(boolean success) throws MailQueueException {
         mailQueueItem.done(success);
         if (success && mandatoryJmapMetaDataIsPresent()) {
-            MessageId messageId = messageIdFactory.fromString((String) getMail().getAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE));
-            String username = (String) getMail().getAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE);
-            if (getMail().getAttribute(IS_DELIVERED) == null) {
+            Optional<?> optionalRawMessageId = retrieveMessageId();
+            MessageId messageId = messageIdFactory.fromString((String) optionalRawMessageId.get());
+            Optional<String> username = retrieveUsername();
+            if (!getMail().getAttribute(IS_DELIVERED.getName()).isPresent()) {
                 try {
-                    MailboxSession mailboxSession = mailboxManager.createSystemSession(username);
+                    MailboxSession mailboxSession = mailboxManager.createSystemSession(username.get());
                     moveFromOutboxToSentWithSeenFlag(messageId, mailboxSession);
-                    getMail().setAttribute(IS_DELIVERED, IS_DELIVERED);
+                    getMail().setAttribute(IS_DELIVERED);
                 } catch (MailShouldBeInOutboxException e) {
                     LOG.info("Message does not exist on Outbox anymore, it could have already been sent", e);
                 } catch (MailboxException e) {
@@ -93,13 +96,26 @@ public class PostDequeueDecorator extends MailQueueItemDecorator {
         }
     }
 
+    private Optional<?> retrieveMessageId() {
+        return AttributeUtils.getAttributeValueFromMail(getMail(), MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE);
+    }
+
+    private Optional<String> retrieveUsername() {
+        return AttributeUtils.getValueAndCastFromMail(getMail(), MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, String.class);
+    }
+
     private boolean mandatoryJmapMetaDataIsPresent() {
         return checkMessageIdAttribute()
             && checkUsernameAttribute();
     }
 
     private boolean checkMessageIdAttribute() {
-        Serializable messageId = getMail().getAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE);
+        return retrieveMessageId()
+            .map(this::validateMessageId)
+            .orElse(false);
+    }
+
+    private boolean validateMessageId(Object messageId) {
         if (messageId instanceof String) {
             try {
                 messageIdFactory.fromString((String) messageId);
@@ -107,15 +123,14 @@ public class PostDequeueDecorator extends MailQueueItemDecorator {
             } catch (Exception e) {
                 LOG.error("Invalid messageId: {}", messageId, e);
             }
-        } else if (messageId != null) {
-            LOG.error("Non-String messageId {} has type {}", messageId, messageId.getClass());
         }
+
+        LOG.error("Non-String messageId {} has type {}", messageId, messageId.getClass());
         return false;
     }
 
     private boolean checkUsernameAttribute() {
-        Serializable username = getMail().getAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE);
-        return (username instanceof String);
+        return retrieveUsername().isPresent();
     }
 
     private void moveFromOutboxToSentWithSeenFlag(MessageId messageId, MailboxSession mailboxSession) throws MailQueueException, MailboxException {
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/SentByJmapTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/SentByJmapTest.java
index b62702c..11ba63d 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/SentByJmapTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/SentByJmapTest.java
@@ -25,6 +25,8 @@ import java.util.Collection;
 
 import org.apache.james.core.MailAddress;
 import org.apache.james.jmap.send.MailMetadata;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.base.MailAddressFixture;
 import org.apache.mailet.base.test.FakeMail;
 import org.apache.mailet.base.test.FakeMailContext;
@@ -49,7 +51,7 @@ public class SentByJmapTest {
         MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
         FakeMail fakeMail = FakeMail.builder()
             .recipient(recipient)
-            .attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, "true")
+            .attribute(new Attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, AttributeValue.of("true")))
             .build();
 
         Collection<MailAddress> results =  testee.match(fakeMail);
@@ -83,7 +85,7 @@ public class SentByJmapTest {
     public void matchShouldReturnEmptyCollectionWhenUserAttributeIsPresentAndThereIsNoRecipient() throws Exception {
         FakeMail fakeMail = FakeMail.builder()
             .recipients()
-            .attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, "true")
+            .attribute(new Attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, AttributeValue.of("true")))
             .build();
 
         Collection<MailAddress> results =  testee.match(fakeMail);
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringExtension.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringExtension.java
index 526c94b..11bff54 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringExtension.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringExtension.java
@@ -68,7 +68,7 @@ public class JMAPFilteringExtension implements BeforeEachCallback, ParameterReso
             this.filteringManagement = filteringManagement;
             this.mailboxManager = mailboxManager;
             try {
-                this.recipient1Mailbox = createMailbox(RECIPIENT_1_USERNAME, RECIPIENT_1_MAILBOX_1);
+                this.recipient1Mailbox = createMailbox(RECIPIENT_1_USERNAME, RECIPIENT_1_MAILBOX_1.value());
             } catch (Exception e) {
                 throw new RuntimeException(e);
             }
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringFixture.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringFixture.java
index 1b4792b..ed5da46 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringFixture.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringFixture.java
@@ -19,6 +19,8 @@
 
 package org.apache.james.jmap.mailet.filter;
 
+import org.apache.mailet.AttributeValue;
+
 public interface JMAPFilteringFixture {
     String GA_BOU_ZO_MEU_FULL_ADDRESS = "GA BOU ZO MEU <GA.BOU.ZO.MEU@james.org>";
     String BOU = "BOU";
@@ -45,7 +47,7 @@ public interface JMAPFilteringFixture {
 
     String RECIPIENT_1 = "recipient1@james.org";
     String RECIPIENT_1_USERNAME = "recipient1";
-    String RECIPIENT_1_MAILBOX_1 = "recipient1_maibox1";
+    AttributeValue<String> RECIPIENT_1_MAILBOX_1 = AttributeValue.of("recipient1_maibox1");
 
     String FRED_MARTIN_FULLNAME = "Frédéric MARTIN";
     String FRED_MARTIN_FULL_SCRAMBLED_ADDRESS = "=?UTF-8?B?RnLDqWTDqXJpYyBNQVJUSU4=?= <fred.martin@linagora.com>";
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
index 0aab648..beae898 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/mailet/filter/JMAPFilteringTest.java
@@ -64,6 +64,9 @@ import org.apache.james.jmap.api.filtering.Rule.Condition.Field;
 import org.apache.james.jmap.mailet.filter.JMAPFilteringExtension.JMAPFilteringTestSystem;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.util.StreamUtils;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.base.RFC2822Headers;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.jupiter.api.Nested;
@@ -80,6 +83,9 @@ import com.google.common.collect.ImmutableList;
 @ExtendWith(JMAPFilteringExtension.class)
 class JMAPFilteringTest {
 
+    private static final AttributeName RECIPIENT_1_USERNAME_ATTRIBUTE_NAME = AttributeName.of(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME);
+    private static final Attribute RECIPIENT_1_MAILBOX_1_ATTRIBUTE = new Attribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME, RECIPIENT_1_MAILBOX_1);
+
     static class FilteringArgumentBuilder {
         private Optional<String> description;
         private Optional<Rule.Condition.Field> field;
@@ -564,8 +570,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo(RECIPIENT_1_MAILBOX_1);
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
     }
 
     @ParameterizedTest(name = "CONTAINS should not match for field {1}: {0}")
@@ -580,8 +586,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isNull();
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .isEmpty();
     }
 
     @ParameterizedTest(name = "NOT-CONTAINS should match for field {1}: {0}")
@@ -595,8 +601,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isEqualTo(RECIPIENT_1_MAILBOX_1);
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
     }
 
 
@@ -612,8 +618,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isNull();
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .isEmpty();
     }
 
     @ParameterizedTest(name = "EXACTLY-EQUALS should match for field {1}: {0}")
@@ -628,8 +634,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isEqualTo(RECIPIENT_1_MAILBOX_1);
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
     }
 
     @ParameterizedTest(name = "EXACTLY-EQUALS should not match for field {1}: {0}")
@@ -643,8 +649,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isNull();
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .isEmpty();
     }
 
     @ParameterizedTest(name = "NOT_EXACTLY_EQUALS should match for field {1}: {0}")
@@ -659,8 +665,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isEqualTo(RECIPIENT_1_MAILBOX_1);
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
     }
 
     @ParameterizedTest(name = "NOT_EXACTLY_EQUALS should not match for field {1}: {0}")
@@ -674,8 +680,8 @@ class JMAPFilteringTest {
         FakeMail mail = testSystem.asMail(mimeMessageBuilder);
         testSystem.getJmapFiltering().service(mail);
 
-        assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-            .isNull();
+        assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+            .isEmpty();
     }
 
     @Nested
@@ -713,8 +719,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo("RECIPIENT_1_MAILBOX_3");
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(new Attribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME, AttributeValue.of("RECIPIENT_1_MAILBOX_3")));
         }
 
         @Test
@@ -739,8 +745,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo("RECIPIENT_1_MAILBOX_1");
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(new Attribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME, AttributeValue.of("RECIPIENT_1_MAILBOX_1")));
         }
 
         @Test
@@ -767,8 +773,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo("RECIPIENT_1_MAILBOX_1");
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(new Attribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME, AttributeValue.of("RECIPIENT_1_MAILBOX_1")));
         }
 
         @Test
@@ -788,8 +794,8 @@ class JMAPFilteringTest {
             FakeMail mail = testSystem.asMail(mimeMessageBuilder());
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isNull();
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .isEmpty();
         }
 
         @Test
@@ -806,8 +812,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isNull();
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .isEmpty();
         }
     }
 
@@ -847,8 +853,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isNull();
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .isEmpty();
         }
 
         @Test
@@ -874,8 +880,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo(RECIPIENT_1_MAILBOX_1);
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
         }
 
         @Test
@@ -897,8 +903,8 @@ class JMAPFilteringTest {
 
             testSystem.getJmapFiltering().service(mail);
 
-            assertThat(mail.getAttribute(DELIVERY_PATH_PREFIX + RECIPIENT_1_USERNAME))
-                .isEqualTo(RECIPIENT_1_MAILBOX_1);
+            assertThat(mail.getAttribute(RECIPIENT_1_USERNAME_ATTRIBUTE_NAME))
+                .contains(RECIPIENT_1_MAILBOX_1_ATTRIBUTE);
         }
     }
 }
\ No newline at end of file
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java
index abc6291..5984cde 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/MailSpoolTest.java
@@ -27,6 +27,8 @@ import org.apache.james.queue.api.MailQueue.MailQueueItem;
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.queue.api.RawMailQueueItemDecoratorFactory;
 import org.apache.james.queue.memory.MemoryMailQueueFactory;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.Before;
 import org.junit.Test;
@@ -69,9 +71,9 @@ public class MailSpoolTest {
 
         MailQueueItem actual = myQueue.deQueue();
         assertThat(actual.getMail().getAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE))
-            .isEqualTo(USERNAME);
+            .contains(new Attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, AttributeValue.of(USERNAME)));
         assertThat(actual.getMail().getAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE))
-            .isEqualTo(MESSAGE_ID.serialize());
+            .contains(new Attribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, AttributeValue.of(MESSAGE_ID.serialize())));
     }
 
 }
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java
index 80affe6..9cae9ac 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/send/PostDequeueDecoratorTest.java
@@ -55,6 +55,8 @@ import org.apache.james.mailbox.store.SystemMailboxesProviderImpl;
 import org.apache.james.mime4j.dom.Message;
 import org.apache.james.queue.api.MailQueue;
 import org.apache.james.queue.api.MailQueue.MailQueueItem;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.Before;
@@ -69,6 +71,7 @@ public class PostDequeueDecoratorTest {
     private static final MessageUid UID = MessageUid.of(1);
     private static final MailboxPath OUTBOX_MAILBOX_PATH = MailboxPath.forUser(USERNAME, OUTBOX);
     private static final MailboxPath SENT_MAILBOX_PATH = MailboxPath.forUser(USERNAME, SENT);
+    private static final Attribute USERNAME_ATTRIBUTE = new Attribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, AttributeValue.of(USERNAME));
     
     private StoreMailboxManager mailboxManager;
     private MailQueueItem mockedMailQueueItem;
@@ -112,8 +115,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(SENT_MAILBOX_PATH, mailboxSession);
         ComposedMessageId sentMessageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, sentMessageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(sentMessageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
         
         testee.done(true);
     }
@@ -124,8 +127,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
 
         testee.done(true);
     }
@@ -137,8 +140,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
         
         testee.done(true);
         
@@ -154,8 +157,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
         
         testee.done(true);
         
@@ -171,8 +174,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
         
         testee.done(false);
         
@@ -203,7 +206,7 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
         
         testee.done(true);
         
@@ -219,7 +222,7 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(USERNAME_ATTRIBUTE);
         
         testee.done(true);
         
@@ -235,8 +238,8 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession);
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, "invalid");
+        mail.setAttribute(USERNAME_ATTRIBUTE);
+        mail.setAttribute(messageIdAttribute("invalid"));
         
         testee.done(true);
         
@@ -256,8 +259,8 @@ public class PostDequeueDecoratorTest {
         MailboxId sentMailboxId = mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession).get();
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
 
         ImmutableList<MessageResult> allMessages = ImmutableList.copyOf(messageManager.getMessages(MessageRange.all(), FetchGroupImpl.MINIMAL, mailboxSession));
 
@@ -284,11 +287,15 @@ public class PostDequeueDecoratorTest {
         mailboxManager.createMailbox(SENT_MAILBOX_PATH, mailboxSession).get();
         MessageManager messageManager = mailboxManager.getMailbox(OUTBOX_MAILBOX_PATH, mailboxSession);
         ComposedMessageId messageId = messageManager.appendMessage(AppendCommand.from(message), mailboxSession);
-        mail.setAttribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, messageId.getMessageId().serialize());
-        mail.setAttribute(MailMetadata.MAIL_METADATA_USERNAME_ATTRIBUTE, USERNAME);
+        mail.setAttribute(messageIdAttribute(messageId.getMessageId().serialize()));
+        mail.setAttribute(USERNAME_ATTRIBUTE);
 
         when(messageIdManager.getMessages(eq(ImmutableList.of(messageId.getMessageId())), eq(FetchGroupImpl.MINIMAL), any(MailboxSession.class))).thenThrow(MailboxException.class);
 
         testee.done(true);
     }
+
+    private Attribute messageIdAttribute(String  value) {
+        return new Attribute(MailMetadata.MAIL_METADATA_MESSAGE_ID_ATTRIBUTE, AttributeValue.of(value));
+    }
 }
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/AddDefaultAttributesMessageHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/AddDefaultAttributesMessageHook.java
index da701fa..1412cdf 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/AddDefaultAttributesMessageHook.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/AddDefaultAttributesMessageHook.java
@@ -23,6 +23,8 @@ import org.apache.commons.configuration.ConfigurationException;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookResult;
 import org.apache.james.server.core.MailImpl;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 
 /**
@@ -53,7 +55,7 @@ public class AddDefaultAttributesMessageHook implements JamesMessageHook {
             mailImpl.setRemoteHost(session.getRemoteAddress().getHostName());
             mailImpl.setRemoteAddr(session.getRemoteAddress().getAddress().getHostAddress());
             if (session.getUser() != null) {
-                mail.setAttribute(Mail.SMTP_AUTH_USER_ATTRIBUTE_NAME, session.getUser());
+                mail.setAttribute(new Attribute(Mail.SMTP_AUTH_USER, AttributeValue.of(session.getUser())));
             }
 
             if (session.isRelayingAllowed()) {
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/MailPriorityHandler.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/MailPriorityHandler.java
index 4959b9e..5230973 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/MailPriorityHandler.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/MailPriorityHandler.java
@@ -33,6 +33,8 @@ import org.apache.james.protocols.api.handler.ProtocolHandler;
 import org.apache.james.protocols.smtp.SMTPSession;
 import org.apache.james.protocols.smtp.hook.HookResult;
 import org.apache.james.queue.api.MailPrioritySupport;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 
 /**
@@ -71,7 +73,7 @@ public class MailPriorityHandler implements JamesMessageHook, ProtocolHandler {
 
         // set the priority if one was found
         if (p != null) {
-            mail.setAttribute(MailPrioritySupport.MAIL_PRIORITY, p);
+            mail.setAttribute(new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.of(p)));
         }
         return HookResult.DECLINED;
     }
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SpamAssassinHandler.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SpamAssassinHandler.java
index ef60371..01718c7 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SpamAssassinHandler.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/fastfail/SpamAssassinHandler.java
@@ -127,9 +127,7 @@ public class SpamAssassinHandler implements JamesMessageHook, ProtocolHandler {
             SpamAssassinResult result = sa.scanMail(message);
 
             // Add the headers
-            for (String key : result.getHeadersAsAttribute().keySet()) {
-                mail.setAttribute(key, result.getHeadersAsAttribute().get(key));
-            }
+            result.getHeadersAsAttributes().forEach(mail::setAttribute);
 
             // Check if rejectionHits was configured
             if (spamdRejectionHits > 0) {
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 db8b783..a257884 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
@@ -18,7 +18,7 @@
  ****************************************************************/
 package org.apache.james.smtpserver;
 
-import static org.apache.james.spamassassin.SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME;
+import static org.apache.james.spamassassin.SpamAssassinResult.STATUS_MAIL;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.HashMap;
@@ -39,6 +39,8 @@ import org.apache.james.smtpserver.fastfail.SpamAssassinHandler;
 import org.apache.james.spamassassin.SpamAssassinResult;
 import org.apache.james.spamassassin.mock.MockSpamd;
 import org.apache.james.spamassassin.mock.MockSpamdTestRule;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.apache.mailet.base.test.FakeMail;
 import org.junit.Rule;
@@ -46,8 +48,11 @@ import org.junit.Test;
 
 public class SpamAssassinHandlerTest {
 
+    private static final String SPAMD_HOST = "localhost";
+    private static final Attribute FLAG_MAIL_ATTRIBUTE_NO = new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("NO"));
+    private static final Attribute FLAG_MAIL_ATTRIBUTE_YES = new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("YES"));
+
     private Mail mockedMail;
-    public static final String SPAMD_HOST = "localhost";
 
     private SMTPSession setupMockedSMTPSession(Mail mail) {
         mockedMail = mail;
@@ -127,8 +132,8 @@ public class SpamAssassinHandlerTest {
         HookResult response = handler.onMessage(session, mockedMail);
 
         assertThat(HookReturnCode.declined()).describedAs("Email was not rejected").isEqualTo(response.getResult());
-        assertThat("NO").describedAs("email was not spam").isEqualTo(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME));
-        assertThat(mockedMail.getAttribute(STATUS_MAIL_ATTRIBUTE_NAME)).withFailMessage("spam hits").isNotNull();
+        assertThat(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL)).describedAs("email was not spam").contains(FLAG_MAIL_ATTRIBUTE_NO);
+        assertThat(mockedMail.getAttribute(STATUS_MAIL)).withFailMessage("spam hits").isPresent();
 
     }
 
@@ -144,8 +149,8 @@ public class SpamAssassinHandlerTest {
         HookResult response = handler.onMessage(session, mockedMail);
 
         assertThat(HookReturnCode.declined()).describedAs("Email was not rejected").isEqualTo(response.getResult());
-        assertThat("YES").describedAs("email was spam").isEqualTo(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME));
-        assertThat(mockedMail.getAttribute(STATUS_MAIL_ATTRIBUTE_NAME)).withFailMessage("spam hits").isNotNull();
+        assertThat(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL)).describedAs("email was spam").contains(FLAG_MAIL_ATTRIBUTE_YES);
+        assertThat(mockedMail.getAttribute(STATUS_MAIL)).withFailMessage("spam hits").isPresent();
     }
 
     @Test
@@ -160,7 +165,7 @@ public class SpamAssassinHandlerTest {
         HookResult response = handler.onMessage(session, mockedMail);
 
         assertThat(HookReturnCode.deny()).describedAs("Email was rejected").isEqualTo(response.getResult());
-        assertThat("YES").describedAs("email was spam").isEqualTo(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME));
-        assertThat(mockedMail.getAttribute(STATUS_MAIL_ATTRIBUTE_NAME)).withFailMessage("spam hits").isNotNull();
+        assertThat(mockedMail.getAttribute(SpamAssassinResult.FLAG_MAIL)).describedAs("email was spam").contains(FLAG_MAIL_ATTRIBUTE_YES);
+        assertThat(mockedMail.getAttribute(STATUS_MAIL)).withFailMessage("spam hits").isPresent();
     }
 }
diff --git a/server/queue/queue-api/src/main/java/org/apache/james/queue/api/MailPrioritySupport.java b/server/queue/queue-api/src/main/java/org/apache/james/queue/api/MailPrioritySupport.java
index 0c22464..ad3f665 100644
--- a/server/queue/queue-api/src/main/java/org/apache/james/queue/api/MailPrioritySupport.java
+++ b/server/queue/queue-api/src/main/java/org/apache/james/queue/api/MailPrioritySupport.java
@@ -18,25 +18,32 @@
  ****************************************************************/
 package org.apache.james.queue.api;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
+
 /**
  * Supports Mail Priority handling
  */
 public interface MailPrioritySupport {
 
+    /**
+     * Attribute name for support if priority. If the attribute is set and
+     * priority handling is enabled it will take care of move the Mails with
+     * higher priority to the head of the queue (so the mails are faster
+     * handled).
+     */
+    AttributeName MAIL_PRIORITY = AttributeName.of("MAIL_PRIORITY");
+
     /** Handle mail with lowest priority */
     int LOW_PRIORITY = 0;
+    Attribute LOW_PRIORITY_ATTRIBUTE = new Attribute(MAIL_PRIORITY, AttributeValue.of(LOW_PRIORITY));
 
     /** Handle mail with normal priority (this is the default) */
     int NORMAL_PRIORITY = 5;
+    Attribute NORMAL_PRIORITY_ATTRIBUTE = new Attribute(MAIL_PRIORITY, AttributeValue.of(NORMAL_PRIORITY));
 
     /** Handle mail with highest priority */
     int HIGH_PRIORITY = 9;
-
-    /**
-     * Attribute name for support if priority. If the attribute is set and
-     * priority handling is enabled it will take care of move the Mails with
-     * higher priority to the head of the queue (so the mails are faster
-     * handled).
-     */
-    String MAIL_PRIORITY = "MAIL_PRIORITY";
+    Attribute HIGH_PRIORITY_ATTRIBUTE = new Attribute(MAIL_PRIORITY, AttributeValue.of(HIGH_PRIORITY));
 }
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/DelayedPriorityMailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/DelayedPriorityMailQueueContract.java
index 895aa88..4ed561c 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/DelayedPriorityMailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/DelayedPriorityMailQueueContract.java
@@ -35,14 +35,14 @@ public interface DelayedPriorityMailQueueContract extends DelayedMailQueueContra
     default void delayedHighPriorityMailShouldBeDeQueuedBeforeLowPriorityNonDelayedMailAfterDelayExpiracy() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY)
+            .attribute(MailPrioritySupport.LOW_PRIORITY_ATTRIBUTE)
             .build());
 
         int delay = 1;
         TimeUnit unit = TimeUnit.SECONDS;
         getMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY)
+            .attribute(MailPrioritySupport.HIGH_PRIORITY_ATTRIBUTE)
             .build(),
             delay,
             unit);
@@ -62,14 +62,14 @@ public interface DelayedPriorityMailQueueContract extends DelayedMailQueueContra
     default void delayedHighPriorityMailShouldBeDeQueuedAfterNonDelayedMail() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.LOW_PRIORITY)
+            .attribute(MailPrioritySupport.LOW_PRIORITY_ATTRIBUTE)
             .build());
 
         int delay = 1;
         TimeUnit unit = TimeUnit.SECONDS;
         getMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, MailPrioritySupport.HIGH_PRIORITY)
+            .attribute(MailPrioritySupport.HIGH_PRIORITY_ATTRIBUTE)
             .build(),
             delay,
             unit);
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
index d6a3ec5..6491502 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/MailQueueContract.java
@@ -147,15 +147,14 @@ public interface MailQueueContract {
 
     @Test
     default void queueShouldPreserveMailAttribute() throws Exception {
-        String attributeName = "any";
-        String attributeValue = "value";
+        Attribute attribute = Attribute.convertToAttribute("any", "value");
         enQueue(defaultMail()
-            .attribute(attributeName, attributeValue)
+            .attribute(attribute)
             .build());
 
         MailQueue.MailQueueItem mailQueueItem = getMailQueue().deQueue();
-        assertThat(mailQueueItem.getMail().getAttribute(attributeName))
-            .isEqualTo(attributeValue);
+        assertThat(mailQueueItem.getMail().getAttribute(attribute.getName()))
+            .contains(attribute);
     }
 
     @Test
@@ -248,16 +247,19 @@ public interface MailQueueContract {
 
     @Test
     default void queueShouldPreserveNonStringMailAttribute() throws Exception {
-        String attributeName = "any";
-        SerializableAttribute attributeValue = new SerializableAttribute("value");
+        Attribute attribute = Attribute.convertToAttribute("any", new SerializableAttribute("value"));
         enQueue(defaultMail()
-                .attribute(attributeName, attributeValue)
+                .attribute(attribute)
                 .build());
 
         MailQueue.MailQueueItem mailQueueItem = getMailQueue().deQueue();
-        assertThat(mailQueueItem.getMail().getAttribute(attributeName))
-                .isInstanceOf(SerializableAttribute.class)
-                .isEqualTo(attributeValue);
+        assertThat(mailQueueItem.getMail().getAttribute(attribute.getName()))
+            .hasValueSatisfying(item -> {
+                assertThat(item)
+                        .isEqualTo(attribute);
+                assertThat(item.getValue().value())
+                        .isInstanceOf(SerializableAttribute.class);
+            });
     }
 
     @Test
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityMailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityMailQueueContract.java
index ffe8fee..01f50bd 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityMailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityMailQueueContract.java
@@ -24,6 +24,8 @@ import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.stream.IntStream;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.junit.jupiter.api.Test;
 
@@ -39,52 +41,52 @@ public interface PriorityMailQueueContract {
     default void priorityShouldReorderMailsWhenDequeing() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name3")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 3)
+            .attribute(mailPriority(3))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name9")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 9)
+            .attribute(mailPriority(9))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 1)
+            .attribute(mailPriority(1))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name8")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 8)
+            .attribute(mailPriority(8))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name6")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 6)
+            .attribute(mailPriority(6))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name0")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 0)
+            .attribute(mailPriority(0))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name7")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 7)
+            .attribute(mailPriority(7))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name4")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 4)
+            .attribute(mailPriority(4))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 2)
+            .attribute(mailPriority(2))
             .build());
 
         getMailQueue().enQueue(defaultMail()
             .name("name5")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 5)
+            .attribute(mailPriority(5))
             .build());
 
         ImmutableList<MailQueue.MailQueueItem> items = IntStream.range(1, 11).boxed()
@@ -105,11 +107,11 @@ public interface PriorityMailQueueContract {
     default void negativePriorityShouldDefaultToMinimumPriority() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name0")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, -1)
+            .attribute(mailPriority(-1))
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 1)
+            .attribute(mailPriority(1))
             .build());
 
         MailQueue.MailQueueItem mailQueueItem1 = getMailQueue().deQueue();
@@ -124,11 +126,11 @@ public interface PriorityMailQueueContract {
     default void tooBigPriorityShouldDefaultToMaximalPriority() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name0")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 12)
+            .attribute(mailPriority(12))
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 8)
+            .attribute(mailPriority(8))
             .build());
 
         MailQueue.MailQueueItem mailQueueItem1 = getMailQueue().deQueue();
@@ -143,15 +145,15 @@ public interface PriorityMailQueueContract {
     default void invalidPriorityShouldDefaultToNormalPriority() throws Exception {
         getMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, "invalid")
+            .attribute(mailPriority("invalid"))
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 4)
+            .attribute(mailPriority(4))
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name3")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 6)
+            .attribute(mailPriority(6))
             .build());
 
         MailQueue.MailQueueItem mailQueueItem1 = getMailQueue().deQueue();
@@ -172,11 +174,11 @@ public interface PriorityMailQueueContract {
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 4)
+            .attribute(mailPriority(4))
             .build());
         getMailQueue().enQueue(defaultMail()
             .name("name3")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 6)
+            .attribute(mailPriority(6))
             .build());
 
         MailQueue.MailQueueItem mailQueueItem1 = getMailQueue().deQueue();
@@ -199,4 +201,8 @@ public interface PriorityMailQueueContract {
         MailQueue.MailQueueItem mailQueueItem = getMailQueue().deQueue();
         assertThat(mailQueueItem.getMail().getName()).isEqualTo("name1");
     }
+
+    default Attribute mailPriority(Object priority) {
+        return new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.ofAny(priority));
+    }
 }
diff --git a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityManageableMailQueueContract.java b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityManageableMailQueueContract.java
index 789bc1d..c9c8c6e 100644
--- a/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityManageableMailQueueContract.java
+++ b/server/queue/queue-api/src/test/java/org/apache/james/queue/api/PriorityManageableMailQueueContract.java
@@ -22,6 +22,8 @@ package org.apache.james.queue.api;
 import static org.apache.james.queue.api.Mails.defaultMail;
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.junit.jupiter.api.Test;
 
@@ -34,52 +36,52 @@ public interface PriorityManageableMailQueueContract extends ManageableMailQueue
     default void browseShouldBeOrderedByPriority() throws Exception {
         getManageableMailQueue().enQueue(defaultMail()
             .name("name3")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 3)
+            .attribute(mailPriority(3))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name9")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 9)
+            .attribute(mailPriority(9))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name1")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 1)
+            .attribute(mailPriority(1))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name8")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 8)
+            .attribute(mailPriority(8))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name6")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 6)
+            .attribute(mailPriority(6))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name0")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 0)
+            .attribute(mailPriority(0))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name7")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 7)
+            .attribute(mailPriority(7))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name4")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 4)
+            .attribute(mailPriority(4))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name2")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 2)
+            .attribute(mailPriority(2))
             .build());
 
         getManageableMailQueue().enQueue(defaultMail()
             .name("name5")
-            .attribute(MailPrioritySupport.MAIL_PRIORITY, 5)
+            .attribute(mailPriority(5))
             .build());
 
         assertThat(getManageableMailQueue().browse())
@@ -87,4 +89,8 @@ public interface PriorityManageableMailQueueContract extends ManageableMailQueue
             .extracting(Mail::getName)
             .containsExactly("name9", "name8", "name7", "name6", "name5", "name4", "name3", "name2", "name1", "name0");
     }
+
+    default Attribute mailPriority(Integer priority) {
+        return new Attribute(MailPrioritySupport.MAIL_PRIORITY, AttributeValue.of(priority));
+    }
 }
diff --git a/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java b/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java
index a863479..f35278c 100644
--- a/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java
+++ b/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSMailQueue.java
@@ -67,6 +67,7 @@ import org.apache.james.server.core.MailImpl;
 import org.apache.james.server.core.MimeMessageCopyOnWriteProxy;
 import org.apache.james.util.SerializationUtil;
 import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeUtils;
 import org.apache.mailet.Mail;
 import org.apache.mailet.PerRecipientHeaders;
 import org.slf4j.Logger;
@@ -252,11 +253,8 @@ public class JMSMailQueue implements ManageableMailQueue, JMSSupport, MailPriori
 
         try {
 
-            int msgPrio = NORMAL_PRIORITY;
-            Object prio = mail.getAttribute(MAIL_PRIORITY);
-            if (prio instanceof Integer) {
-                msgPrio = (Integer) prio;
-            }
+            int msgPrio = AttributeUtils.getValueAndCastFromMail(mail, MAIL_PRIORITY, Integer.class)
+                .orElse(NORMAL_PRIORITY);
 
             Map<String, Object> props = getJMSProperties(mail, nextDeliveryTimestamp);
             produceMail(props, msgPrio, mail);
diff --git a/third-party/spamassassin/pom.xml b/third-party/spamassassin/pom.xml
index 5bfd2e8..0d70747 100644
--- a/third-party/spamassassin/pom.xml
+++ b/third-party/spamassassin/pom.xml
@@ -31,6 +31,10 @@
     <dependencies>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>apache-mailet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>james-core</artifactId>
         </dependency>
         <dependency>
diff --git a/third-party/spamassassin/src/main/java/org/apache/james/spamassassin/SpamAssassinResult.java b/third-party/spamassassin/src/main/java/org/apache/james/spamassassin/SpamAssassinResult.java
index 96f98ea..b246249 100644
--- a/third-party/spamassassin/src/main/java/org/apache/james/spamassassin/SpamAssassinResult.java
+++ b/third-party/spamassassin/src/main/java/org/apache/james/spamassassin/SpamAssassinResult.java
@@ -18,17 +18,21 @@
  ****************************************************************/
 package org.apache.james.spamassassin;
 
-import java.util.Map;
+import java.util.List;
+
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeValue;
 
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableList;
 
 public class SpamAssassinResult {
     /** The mail attribute under which the status get stored */
-    public static final String STATUS_MAIL_ATTRIBUTE_NAME = "org.apache.james.spamassassin.status";
+    public static final AttributeName STATUS_MAIL = AttributeName.of("org.apache.james.spamassassin.status");
 
     /** The mail attribute under which the flag get stored */
-    public static final String FLAG_MAIL_ATTRIBUTE_NAME = "org.apache.james.spamassassin.flag";
+    public static final AttributeName FLAG_MAIL = AttributeName.of("org.apache.james.spamassassin.flag");
 
     public static final String NO_RESULT = "?";
 
@@ -71,27 +75,27 @@ public class SpamAssassinResult {
             Preconditions.checkNotNull(hits);
             Preconditions.checkNotNull(requiredHits);
 
-            ImmutableMap.Builder<String, String> headersAsAttribute = ImmutableMap.builder();
+            ImmutableList.Builder<Attribute> headersAsAttributes = ImmutableList.builder();
             if (isSpam) {
-                headersAsAttribute.put(FLAG_MAIL_ATTRIBUTE_NAME, "YES");
-                headersAsAttribute.put(STATUS_MAIL_ATTRIBUTE_NAME, "Yes, hits=" + hits + " required=" + requiredHits);
+                headersAsAttributes.add(new Attribute(FLAG_MAIL, AttributeValue.of("YES")));
+                headersAsAttributes.add(new Attribute(STATUS_MAIL, AttributeValue.of("Yes, hits=" + hits + " required=" + requiredHits)));
             } else {
-                headersAsAttribute.put(FLAG_MAIL_ATTRIBUTE_NAME, "NO");
-                headersAsAttribute.put(STATUS_MAIL_ATTRIBUTE_NAME, "No, hits=" + hits + " required=" + requiredHits);
+                headersAsAttributes.add(new Attribute(FLAG_MAIL, AttributeValue.of("NO")));
+                headersAsAttributes.add(new Attribute(STATUS_MAIL, AttributeValue.of("No, hits=" + hits + " required=" + requiredHits)));
             }
 
-            return new SpamAssassinResult(hits, requiredHits, headersAsAttribute.build());
+            return new SpamAssassinResult(hits, requiredHits, headersAsAttributes.build());
         }
     }
 
     private final String hits;
     private final String requiredHits;
-    private final Map<String, String> headersAsAttribute;
+    private final List<Attribute> headersAsAttributes;
 
-    private SpamAssassinResult(String hits, String requiredHits, Map<String, String> headersAsAttribute) {
+    private SpamAssassinResult(String hits, String requiredHits, List<Attribute> headersAsAttributes) {
         this.hits = hits;
         this.requiredHits = requiredHits;
-        this.headersAsAttribute = headersAsAttribute;
+        this.headersAsAttributes = headersAsAttributes;
     }
 
     public String getHits() {
@@ -102,8 +106,8 @@ public class SpamAssassinResult {
         return requiredHits;
     }
 
-    public Map<String, String> getHeadersAsAttribute() {
-        return headersAsAttribute;
+    public List<Attribute> getHeadersAsAttributes() {
+        return headersAsAttributes;
     }
 
 }
diff --git a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinInvokerTest.java b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinInvokerTest.java
index cb3bbdc..26af030 100644
--- a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinInvokerTest.java
+++ b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinInvokerTest.java
@@ -29,6 +29,8 @@ import org.apache.james.core.User;
 import org.apache.james.metrics.api.NoopMetricFactory;
 import org.apache.james.spamassassin.SpamAssassinExtension.SpamAssassin;
 import org.apache.james.util.MimeMessageUtil;
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
@@ -71,7 +73,7 @@ public class SpamAssassinInvokerTest {
                 ClassLoader.getSystemResourceAsStream("eml/spam.eml"));
         SpamAssassinResult result = testee.scanMail(mimeMessage, USER);
 
-        assertThat(result.getHeadersAsAttribute()).isNotEmpty();
+        assertThat(result.getHeadersAsAttributes()).isNotEmpty();
     }
 
     @Disabled("MAILBOX-377 This test is not stable, fails on our CI and thus is temporarily disabled")
@@ -84,7 +86,7 @@ public class SpamAssassinInvokerTest {
 
         SpamAssassinResult result = testee.scanMail(mimeMessage, USER);
 
-        assertThat(result.getHeadersAsAttribute().get(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)).isEqualTo("YES");
+        assertThat(result.getHeadersAsAttributes()).contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("YES")));
     }
 
     @Test
@@ -108,7 +110,7 @@ public class SpamAssassinInvokerTest {
 
         SpamAssassinResult result = testee.scanMail(mimeMessage, USER);
 
-        assertThat(result.getHeadersAsAttribute().get(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)).isEqualTo("YES");
+        assertThat(result.getHeadersAsAttributes()).contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("YES")));
     }
 
     @Test
@@ -130,7 +132,7 @@ public class SpamAssassinInvokerTest {
 
         SpamAssassinResult result = testee.scanMail(mimeMessage, USER);
 
-        assertThat(result.getHeadersAsAttribute().get(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)).isEqualTo("NO");
+        assertThat(result.getHeadersAsAttributes()).contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("NO")));
     }
 
     @Test
@@ -145,6 +147,6 @@ public class SpamAssassinInvokerTest {
 
         SpamAssassinResult result = testee.scanMail(mimeMessage, USER);
 
-        assertThat(result.getHeadersAsAttribute().get(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME)).isEqualTo("NO");
+        assertThat(result.getHeadersAsAttributes()).contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("NO")));
     }
 }
diff --git a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinResultTest.java b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinResultTest.java
index fb75604..470f8c9 100644
--- a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinResultTest.java
+++ b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinResultTest.java
@@ -21,12 +21,12 @@ package org.apache.james.spamassassin;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
+import org.apache.mailet.Attribute;
+import org.apache.mailet.AttributeValue;
 import org.assertj.core.api.JUnitSoftAssertions;
 import org.junit.Rule;
 import org.junit.Test;
 
-import com.google.common.collect.ImmutableMap;
-
 public class SpamAssassinResultTest {
 
     @Rule
@@ -60,10 +60,10 @@ public class SpamAssassinResultTest {
 
         softly.assertThat(spamAssassinResult.getHits()).isEqualTo(hits);
         softly.assertThat(spamAssassinResult.getRequiredHits()).isEqualTo(requiredHits);
-        softly.assertThat(spamAssassinResult.getHeadersAsAttribute())
-            .containsAllEntriesOf(ImmutableMap.of(
-                SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME, "YES",
-                SpamAssassinResult.STATUS_MAIL_ATTRIBUTE_NAME, "Yes, hits=1.1 required=5.0"));
+        softly.assertThat(spamAssassinResult.getHeadersAsAttributes())
+            .containsOnly(
+                new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("YES")),
+                new Attribute(SpamAssassinResult.STATUS_MAIL, AttributeValue.of("Yes, hits=1.1 required=5.0")));
     }
 
     @Test
@@ -76,8 +76,8 @@ public class SpamAssassinResultTest {
             .requiredHits(requiredHits)
             .build();
 
-        assertThat(spamAssassinResult.getHeadersAsAttribute())
-            .containsEntry(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME, "YES");
+        assertThat(spamAssassinResult.getHeadersAsAttributes())
+            .contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("YES")));
     }
 
     @Test
@@ -90,7 +90,7 @@ public class SpamAssassinResultTest {
             .requiredHits(requiredHits)
             .build();
 
-        assertThat(spamAssassinResult.getHeadersAsAttribute())
-            .containsEntry(SpamAssassinResult.FLAG_MAIL_ATTRIBUTE_NAME, "NO");
+        assertThat(spamAssassinResult.getHeadersAsAttributes())
+            .contains(new Attribute(SpamAssassinResult.FLAG_MAIL, AttributeValue.of("NO")));
     }
 }


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


Mime
View raw message