diff --git a/composer.json b/composer.json
index dd114b6810b569cf5c8fd97cebe915b1e78b5e0d..f9d1ae4c8fdb1a068e66cacba1ff9144ae549396 100644
--- a/composer.json
+++ b/composer.json
@@ -50,7 +50,8 @@
         "symfony/mailer": "^7.0",
         "symfony/messenger": "^7.0",
         "symfony/http-client": "^7.0",
-        "rubix/ml": "^2.4"
+        "rubix/ml": "^2.4",
+        "grpc/grpc": "^1.57"
     },
     "require-dev": {
         "mockery/mockery": "^1.6",
diff --git a/composer.lock b/composer.lock
index fbf586959de452a362edc5761f77c98e1eae8b84..1dcec6f9c896b95b060e576de229b31e58f2747b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "2008e1dfe7cb51ec6de8a61bdd663c0e",
+    "content-hash": "8d3f949c2f347224492b51e19ad57c76",
     "packages": [
         {
             "name": "amphp/amp",
@@ -1973,6 +1973,50 @@
             },
             "time": "2023-11-17T15:01:25+00:00"
         },
+        {
+            "name": "grpc/grpc",
+            "version": "1.57.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/grpc/grpc-php.git",
+                "reference": "b610c42022ed3a22f831439cb93802f2a4502fdf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/grpc/grpc-php/zipball/b610c42022ed3a22f831439cb93802f2a4502fdf",
+                "reference": "b610c42022ed3a22f831439cb93802f2a4502fdf",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0.0"
+            },
+            "require-dev": {
+                "google/auth": "^v1.3.0"
+            },
+            "suggest": {
+                "ext-protobuf": "For better performance, install the protobuf C extension.",
+                "google/protobuf": "To get started using grpc quickly, install the native protobuf library."
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Grpc\\": "src/lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache-2.0"
+            ],
+            "description": "gRPC library for PHP",
+            "homepage": "https://grpc.io",
+            "keywords": [
+                "rpc"
+            ],
+            "support": {
+                "source": "https://github.com/grpc/grpc-php/tree/v1.57.0"
+            },
+            "time": "2023-08-14T23:57:54+00:00"
+        },
         {
             "name": "guzzlehttp/guzzle",
             "version": "7.8.1",
diff --git a/docs/pages/docs/features/grpc/index.md b/docs/pages/docs/features/grpc/index.md
index c131b05560feed074eef0261cb9a1cab13136c05..d5f780cf4c8893ab067ca81e2fb46d7894e8d859 100644
--- a/docs/pages/docs/features/grpc/index.md
+++ b/docs/pages/docs/features/grpc/index.md
@@ -1,7 +1,6 @@
 ---
 collections:
     - documents
-draft: true
 layout: dm:document
 parent: docs/features/index
 title: gRPC
@@ -16,6 +15,8 @@ description: >
 You can find instruction on the official 
 [Google documentation page](https://cloud.google.com/php/grpc).
 
+## PHP Extensions
+
 On Debian-based systems:
 
 ```shell
@@ -24,4 +25,30 @@ $ sudo pecl install grpc
 $ sudo pecl install protobuf
 ```
 
+Enable both `grpc.so` and `protobuf.so` plugins in your php.ini config.
+
+## Protocol Buffers Compiler
+
+```shell
+$ sudo apt install protobuf-compiler
+```
+
+## GRPC PHP Plugin
+
+You need to clone https://github.com/grpc/grpc repo, then follow their build
+instructions from https://github.com/grpc/grpc/blob/v1.61.0/src/php/README.md 
+
+You can use [bazel](https://bazel.build/) to build the plugin.
+
+```shell
+$ sudo apt install bazel-bootstrap clang
+```
+
+Then, in the folder with `grpc/grpc`:
+
+```shell
+$ bazel build @com_google_protobuf//:protoc
+$ bazel build src/compiler:grpc_php_plugin
+```
+
 #  Usage
diff --git a/src/Attribute/GrantsFeature.php b/src/Attribute/GrantsFeature.php
index 3fbe02860176198a5dc7ddf5d4a8db02d2893872..3f0146b716ad6665cd0cfddc4fbb31e3b8414577 100644
--- a/src/Attribute/GrantsFeature.php
+++ b/src/Attribute/GrantsFeature.php
@@ -8,7 +8,7 @@ use Attribute;
 use Distantmagic\Resonance\Attribute as BaseAttribute;
 use Distantmagic\Resonance\FeatureInterface;
 
-#[Attribute(Attribute::TARGET_CLASS)]
+#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
 final readonly class GrantsFeature extends BaseAttribute
 {
     public function __construct(
diff --git a/src/Attribute/TestableHttpResponse.php b/src/Attribute/TestsHttpResponse.php
similarity index 53%
rename from src/Attribute/TestableHttpResponse.php
rename to src/Attribute/TestsHttpResponse.php
index 243a1ccd6b5fd719190a6a570a76305efbcd4065..a06750e5ac3fb3e014d301a6e1967b76cf085b1d 100644
--- a/src/Attribute/TestableHttpResponse.php
+++ b/src/Attribute/TestsHttpResponse.php
@@ -7,5 +7,5 @@ namespace Distantmagic\Resonance\Attribute;
 use Attribute;
 use Distantmagic\Resonance\Attribute as BaseAttribute;
 
-#[Attribute(Attribute::IS_REPEATABLE | Attribute::TARGET_CLASS)]
-final readonly class TestableHttpResponse extends BaseAttribute {}
+#[Attribute(Attribute::TARGET_CLASS)]
+final readonly class TestsHttpResponse extends BaseAttribute {}
diff --git a/src/Command/GrpcGenerate.php b/src/Command/GrpcGenerate.php
new file mode 100644
index 0000000000000000000000000000000000000000..6078bd36263114f9eb419d4c3cd7f1c55e44b58f
--- /dev/null
+++ b/src/Command/GrpcGenerate.php
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Distantmagic\Resonance\Command;
+
+use Distantmagic\Resonance\Attribute\ConsoleCommand;
+use Distantmagic\Resonance\Attribute\WantsFeature;
+use Distantmagic\Resonance\Command;
+use Distantmagic\Resonance\Feature;
+use Nette\PhpGenerator\Printer;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+#[ConsoleCommand(
+    name: 'grpc:generate',
+    description: 'Generate GRPC stubs'
+)]
+#[WantsFeature(Feature::Grpc)]
+final class GrpcGenerate extends Command
+{
+    public function __construct(private readonly Printer $printer)
+    {
+        parent::__construct();
+    }
+
+    protected function configure(): void {}
+
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        return Command::SUCCESS;
+    }
+}
diff --git a/src/Command/MailSend.php b/src/Command/MailSend.php
index dd5644bfe45e383d8130a477b4ae9b3d5539ab99..8aab03a78fc26b58b673d2506b1b85068f0edcb4 100644
--- a/src/Command/MailSend.php
+++ b/src/Command/MailSend.php
@@ -5,7 +5,9 @@ declare(strict_types=1);
 namespace Distantmagic\Resonance\Command;
 
 use Distantmagic\Resonance\Attribute\ConsoleCommand;
+use Distantmagic\Resonance\Attribute\WantsFeature;
 use Distantmagic\Resonance\Command;
+use Distantmagic\Resonance\Feature;
 use Distantmagic\Resonance\MailerRepository;
 use RuntimeException;
 use Swoole\Event;
@@ -19,6 +21,7 @@ use Symfony\Component\Mime\Email;
     name: 'mail:send',
     description: 'Send email using the selected transport'
 )]
+#[WantsFeature(Feature::Mailer)]
 final class MailSend extends Command
 {
     public function __construct(
diff --git a/src/Command/TestHttpResponders.php b/src/Command/TestHttpResponders.php
index ef0e27a0ac53bbb6e943584041b3cc2ecab04e0b..ab192b323721eebf4adce13e5c0f3b913800741f 100644
--- a/src/Command/TestHttpResponders.php
+++ b/src/Command/TestHttpResponders.php
@@ -12,7 +12,7 @@ use Distantmagic\Resonance\HttpResponderAggregate;
 use Distantmagic\Resonance\HttpResponderInterface;
 use Distantmagic\Resonance\InspectableSwooleResponse;
 use Distantmagic\Resonance\SwooleCoroutineHelper;
-use Distantmagic\Resonance\TestableHttpResponseCollection;
+use Distantmagic\Resonance\TestsHttpResponseCollection;
 use Ds\Map;
 use RuntimeException;
 use Swoole\Http\Request;
@@ -28,7 +28,7 @@ final class TestHttpResponders extends Command
     public function __construct(
         private readonly HttpRecursiveResponder $recursiveResponder,
         private readonly HttpResponderAggregate $httpResponderAggregate,
-        private readonly TestableHttpResponseCollection $testableHttpResponseCollection,
+        private readonly TestsHttpResponseCollection $testsHttpResponseCollection,
     ) {
         parent::__construct();
     }
@@ -40,12 +40,12 @@ final class TestHttpResponders extends Command
          */
         $isValid = true;
 
-        foreach ($this->testableHttpResponseCollection->httpResponder as $httpResponder => $testableHttpResponses) {
-            foreach ($testableHttpResponses as $testableHttpResponse) {
+        foreach ($this->testsHttpResponseCollection->httpResponder as $httpResponder => $testsHttpResponses) {
+            foreach ($testsHttpResponses as $testsHttpResponse) {
                 $potentialResponses = $this
-                    ->testableHttpResponseCollection
-                    ->testableHttpResponse
-                    ->get($testableHttpResponse)
+                    ->testsHttpResponseCollection
+                    ->testsHttpResponse
+                    ->get($testsHttpResponse)
                 ;
 
                 $result = SwooleCoroutineHelper::mustRun(function () use (
diff --git a/src/DependencyInjectionContainer.php b/src/DependencyInjectionContainer.php
index 8f736643ed565f5e488abd7d1e3834edc5c01ef2..61b470710576045088a7aeca1686e87163682515 100644
--- a/src/DependencyInjectionContainer.php
+++ b/src/DependencyInjectionContainer.php
@@ -13,7 +13,6 @@ use Ds\Set;
 use ReflectionClass;
 use ReflectionFunction;
 use ReflectionFunctionAbstract;
-use RuntimeException;
 use Swoole\Event;
 
 readonly class DependencyInjectionContainer
@@ -113,8 +112,8 @@ readonly class DependencyInjectionContainer
                 throw new AmbiguousProvider($providedClassName);
             }
 
-            if ($dependencyProvider->wantsFeature) {
-                $this->enableFeature($dependencyProvider->wantsFeature);
+            foreach ($dependencyProvider->wantsFeatures as $wantedFeature) {
+                $this->enableFeature($wantedFeature);
             }
 
             $this->dependencyProviders->put($providedClassName, $dependencyProvider);
@@ -191,11 +190,17 @@ readonly class DependencyInjectionContainer
 
     private function isDependencyProviderWanted(DependencyProvider $dependencyProvider): bool
     {
-        if (is_null($dependencyProvider->grantsFeature)) {
+        if ($dependencyProvider->grantsFeatures->isEmpty()) {
             return true;
         }
 
-        return $this->wantedFeatures->contains($dependencyProvider->grantsFeature);
+        foreach ($dependencyProvider->grantsFeatures as $grantedFeature) {
+            if ($this->wantedFeatures->contains($grantedFeature)) {
+                return true;
+            }
+        }
+
+        return false;
     }
 
     /**
@@ -272,13 +277,9 @@ readonly class DependencyInjectionContainer
         }
 
         if (!$this->isDependencyProviderWanted($dependencyProvider)) {
-            if (!$dependencyProvider->grantsFeature) {
-                throw new RuntimeException('Classname with no provider, not wanted: '.$className);
-            }
-
             throw new DisabledFeatureProvider(
                 $className,
-                $dependencyProvider->grantsFeature,
+                $dependencyProvider->grantsFeatures->diff($this->wantedFeatures),
                 $stack,
             );
         }
diff --git a/src/DependencyInjectionContainerException/DisabledFeatureProvider.php b/src/DependencyInjectionContainerException/DisabledFeatureProvider.php
index c710648d6b3b9e3391c560c8533892b1dcb10b10..e28eb929ee996e09e999b46e6848355ecff069bc 100644
--- a/src/DependencyInjectionContainerException/DisabledFeatureProvider.php
+++ b/src/DependencyInjectionContainerException/DisabledFeatureProvider.php
@@ -7,27 +7,49 @@ namespace Distantmagic\Resonance\DependencyInjectionContainerException;
 use Distantmagic\Resonance\DependencyInjectionContainerException;
 use Distantmagic\Resonance\DependencyStack;
 use Distantmagic\Resonance\FeatureInterface;
+use Ds\Set;
 use Throwable;
 
 class DisabledFeatureProvider extends DependencyInjectionContainerException
 {
     /**
-     * @param class-string $className
+     * @param class-string          $className
+     * @param Set<FeatureInterface> $features
      */
     public function __construct(
         string $className,
-        FeatureInterface $feature,
+        Set $features,
         DependencyStack $stack,
         ?Throwable $previous = null,
     ) {
         parent::__construct(
             sprintf(
-                "Enable '%s' feature to use this provider:\n-> %s\nDependency stack:\n-> %s\n",
-                $feature->getName(),
+                "Enable '%s' %s to use this provider:\n-> %s\nDependency stack:\n-> %s\n",
+                $this->serializeFeatures($features)->join("', '"),
+                1 === $features->count() ? 'feature' : 'features',
                 $className,
                 $stack->join("\n-> "),
             ),
             $previous
         );
     }
+
+    /**
+     * @param Set<FeatureInterface> $features
+     *
+     * @return Set<non-empty-string>
+     */
+    private function serializeFeatures(Set $features): Set
+    {
+        /**
+         * @var Set<non-empty-string>
+         */
+        $ret = new Set();
+
+        foreach ($features as $feature) {
+            $ret->add($feature->getName());
+        }
+
+        return $ret;
+    }
 }
diff --git a/src/DependencyProvider.php b/src/DependencyProvider.php
index 4efa02fa14fdf7f5b68a3b784bf09690df2f05c0..1ceaa9fc6c5e375bd0d3109b54a2657141b74cf8 100644
--- a/src/DependencyProvider.php
+++ b/src/DependencyProvider.php
@@ -10,15 +10,17 @@ use ReflectionClass;
 readonly class DependencyProvider
 {
     /**
+     * @param Set<FeatureInterface>             $grantsFeatures
      * @param Set<SingletonCollectionInterface> $requiredCollections
      * @param class-string                      $providedClassName
+     * @param Set<FeatureInterface>             $wantsFeatures
      */
     public function __construct(
-        public ?FeatureInterface $grantsFeature,
+        public Set $grantsFeatures,
         public ReflectionClass $providerReflectionClass,
         public Set $requiredCollections,
         public ?SingletonCollectionInterface $collection,
         public string $providedClassName,
-        public ?FeatureInterface $wantsFeature,
+        public Set $wantsFeatures,
     ) {}
 }
diff --git a/src/DependencyProviderIterator.php b/src/DependencyProviderIterator.php
index 1d7a41bdfab1d8620395d28c5986a2f223e44d1b..b271a12055240a0c568ee1326bb60e0a9886ee7b 100644
--- a/src/DependencyProviderIterator.php
+++ b/src/DependencyProviderIterator.php
@@ -30,11 +30,11 @@ readonly class DependencyProviderIterator implements IteratorAggregate
 
             yield $providedClassName => new DependencyProvider(
                 collection: $reflectionAttribute->attribute->collection,
-                grantsFeature: $reflectionClassAttributeManager->findAttribute(GrantsFeature::class)?->feature,
+                grantsFeatures: $this->pluckFeature($reflectionClassAttributeManager->findAttributes(GrantsFeature::class)),
                 providedClassName: $providedClassName,
                 providerReflectionClass: $reflectionAttribute->reflectionClass,
                 requiredCollections: $this->findRequiredCollections($reflectionClassAttributeManager),
-                wantsFeature: $reflectionClassAttributeManager->findAttribute(WantsFeature::class)?->feature,
+                wantsFeatures: $this->pluckFeature($reflectionClassAttributeManager->findAttributes(WantsFeature::class)),
             );
         }
     }
@@ -57,4 +57,23 @@ readonly class DependencyProviderIterator implements IteratorAggregate
 
         return $requiredCollections;
     }
+
+    /**
+     * @param Set<GrantsFeature>|Set<WantsFeature> $attributes
+     *
+     * @return Set<FeatureInterface>
+     */
+    private function pluckFeature(Set $attributes): Set
+    {
+        /**
+         * @var Set<FeatureInterface>
+         */
+        $ret = new Set();
+
+        foreach ($attributes as $attribute) {
+            $ret->add($attribute->feature);
+        }
+
+        return $ret;
+    }
 }
diff --git a/src/Feature.php b/src/Feature.php
index fc72fa54bc5f9a4ad668128c223d4c9b2064f24e..a18b1a66895227de3531d73a72cb391c96e2d78c 100644
--- a/src/Feature.php
+++ b/src/Feature.php
@@ -6,16 +6,15 @@ namespace Distantmagic\Resonance;
 
 enum Feature implements FeatureInterface
 {
+    use NameableEnumTrait;
+
     case Doctrine;
+    case Grpc;
     case HttpSession;
+    case Mailer;
     case OAuth2;
     case Postfix;
     case StaticPages;
     case SwooleTaskServer;
     case WebSocket;
-
-    public function getName(): string
-    {
-        return $this->name;
-    }
 }
diff --git a/src/FeatureInterface.php b/src/FeatureInterface.php
index e58b18837d6dcea3ecab811cb00a0adb9c7583d8..0b56c536ce6f896f50e480c9a6a570dde889a006 100644
--- a/src/FeatureInterface.php
+++ b/src/FeatureInterface.php
@@ -4,7 +4,4 @@ declare(strict_types=1);
 
 namespace Distantmagic\Resonance;
 
-interface FeatureInterface
-{
-    public function getName(): string;
-}
+interface FeatureInterface extends NameableInterface {}
diff --git a/src/NameableEnumTrait.php b/src/NameableEnumTrait.php
index 45368bac289973775a69ef6992f3a64a4aef0b46..4207f14e1886999a24cc92c58e1e0d5435faf174 100644
--- a/src/NameableEnumTrait.php
+++ b/src/NameableEnumTrait.php
@@ -6,6 +6,9 @@ namespace Distantmagic\Resonance;
 
 trait NameableEnumTrait
 {
+    /**
+     * @return non-empty-string
+     */
     public function getName(): string
     {
         return $this->name;
diff --git a/src/NameableInterface.php b/src/NameableInterface.php
index e871e0774ca0bd7951fe75ad10672c3c96ce1145..0f41001d6dd652e35e7b8f0266d0ef97caac4fc2 100644
--- a/src/NameableInterface.php
+++ b/src/NameableInterface.php
@@ -6,5 +6,8 @@ namespace Distantmagic\Resonance;
 
 interface NameableInterface
 {
+    /**
+     * @return non-empty-string
+     */
     public function getName(): string;
 }
diff --git a/src/ServerTaskHandler/SendsEmailMessage.php b/src/ServerTaskHandler/SendsEmailMessage.php
index 776f0f4b8998e2c907a359ea1ab71a103d4c6c6c..1b1bfa659d9f29d79fee0f96d7a5cc5b1575f2ff 100644
--- a/src/ServerTaskHandler/SendsEmailMessage.php
+++ b/src/ServerTaskHandler/SendsEmailMessage.php
@@ -17,6 +17,7 @@ use Distantmagic\Resonance\SingletonCollection;
  * @template-extends ServerTaskHandler<SendEmailMessage>
  */
 #[GrantsFeature(Feature::SwooleTaskServer)]
+#[GrantsFeature(Feature::Mailer)]
 #[HandlesServerTask(SendEmailMessage::class)]
 #[Singleton(collection: SingletonCollection::ServerTaskHandler)]
 readonly class SendsEmailMessage extends ServerTaskHandler
diff --git a/src/SingletonProvider/ConfigurationProvider/MailerConfigurationProvider.php b/src/SingletonProvider/ConfigurationProvider/MailerConfigurationProvider.php
index 5ef41c5de9fcc555ed18ad7c872f944c45f7c952..1aa00bf873ed0a492f47f38f113e5bae1b280720 100644
--- a/src/SingletonProvider/ConfigurationProvider/MailerConfigurationProvider.php
+++ b/src/SingletonProvider/ConfigurationProvider/MailerConfigurationProvider.php
@@ -4,11 +4,13 @@ declare(strict_types=1);
 
 namespace Distantmagic\Resonance\SingletonProvider\ConfigurationProvider;
 
+use Distantmagic\Resonance\Attribute\GrantsFeature;
 use Distantmagic\Resonance\Attribute\Singleton;
 use Distantmagic\Resonance\Constraint;
 use Distantmagic\Resonance\Constraint\MapConstraint;
 use Distantmagic\Resonance\Constraint\ObjectConstraint;
 use Distantmagic\Resonance\Constraint\StringConstraint;
+use Distantmagic\Resonance\Feature;
 use Distantmagic\Resonance\MailerConfiguration;
 use Distantmagic\Resonance\MailerTransportConfiguration;
 use Distantmagic\Resonance\SingletonProvider\ConfigurationProvider;
@@ -26,6 +28,7 @@ use Distantmagic\Resonance\SingletonProvider\ConfigurationProvider;
  *     }>
  * >
  */
+#[GrantsFeature(Feature::Mailer)]
 #[Singleton(provides: MailerConfiguration::class)]
 final readonly class MailerConfigurationProvider extends ConfigurationProvider
 {
diff --git a/src/SingletonProvider/EventListenerAggregateProvider.php b/src/SingletonProvider/EventListenerAggregateProvider.php
index acbe6ed7480fbd835e22db1f6f7edc199d50b4b8..f8cb8b46c072817b056108a43b2e3b01dc865c7a 100644
--- a/src/SingletonProvider/EventListenerAggregateProvider.php
+++ b/src/SingletonProvider/EventListenerAggregateProvider.php
@@ -22,9 +22,6 @@ use Distantmagic\Resonance\SingletonProvider;
 #[Singleton(provides: EventListenerAggregate::class)]
 final readonly class EventListenerAggregateProvider extends SingletonProvider
 {
-    public function __construct(
-    ) {}
-
     public function provide(SingletonContainer $singletons, PHPProjectFiles $phpProjectFiles): EventListenerAggregate
     {
         $eventListenerAggregate = new EventListenerAggregate();
diff --git a/src/SingletonProvider/MailerRepositoryProvider.php b/src/SingletonProvider/MailerRepositoryProvider.php
index 8850a8b837848842ee7b9175120a0a55685a9595..1ed0c7bb5f36442a7681ab1b706cecdcdb84aa60 100644
--- a/src/SingletonProvider/MailerRepositoryProvider.php
+++ b/src/SingletonProvider/MailerRepositoryProvider.php
@@ -4,7 +4,10 @@ declare(strict_types=1);
 
 namespace Distantmagic\Resonance\SingletonProvider;
 
+use Distantmagic\Resonance\Attribute\GrantsFeature;
 use Distantmagic\Resonance\Attribute\Singleton;
+use Distantmagic\Resonance\DependencyInjectionContainer;
+use Distantmagic\Resonance\Feature;
 use Distantmagic\Resonance\Mailer;
 use Distantmagic\Resonance\MailerConfiguration;
 use Distantmagic\Resonance\MailerRepository;
@@ -16,17 +19,18 @@ use Distantmagic\Resonance\SwooleTaskServerMessageBus;
 use Psr\Log\LoggerInterface;
 use RuntimeException;
 use Symfony\Component\Mailer\Transport;
-use Symfony\Component\Mailer\Transport\TransportInterface;
 use Symfony\Component\Mime\Crypto\DkimSigner;
 use Symfony\Contracts\HttpClient\HttpClientInterface;
 
 /**
  * @template-extends SingletonProvider<MailerRepository>
  */
+#[GrantsFeature(Feature::Mailer)]
 #[Singleton(provides: MailerRepository::class)]
 final readonly class MailerRepositoryProvider extends SingletonProvider
 {
     public function __construct(
+        private DependencyInjectionContainer $dependencyInjectionContainer,
         private HttpClientInterface $httpClient,
         private LoggerInterface $logger,
         private MailerConfiguration $mailerConfiguration,
@@ -44,7 +48,12 @@ final readonly class MailerRepositoryProvider extends SingletonProvider
                     dkimSigner: $this->buildDkimSigner($name, $transportConfiguration),
                     name: $name,
                     messageBus: $this->swooleTaskServerMessageBus,
-                    transport: $this->buildTransport($transportConfiguration),
+                    transport: Transport::fromDsn(
+                        client: $this->httpClient,
+                        // dispatcher: $eventDispatcher,
+                        dsn: $transportConfiguration->transportDsn,
+                        logger: $this->logger,
+                    ),
                 )
             );
         }
@@ -89,13 +98,4 @@ final readonly class MailerRepositoryProvider extends SingletonProvider
             $name,
         ));
     }
-
-    private function buildTransport(MailerTransportConfiguration $transportConfiguration): TransportInterface
-    {
-        return Transport::fromDsn(
-            client: $this->httpClient,
-            dsn: $transportConfiguration->transportDsn,
-            logger: $this->logger,
-        );
-    }
 }
diff --git a/src/SingletonProvider/TestableHttpResponseCollectionProvider.php b/src/SingletonProvider/TestsHttpResponseCollectionProvider.php
similarity index 80%
rename from src/SingletonProvider/TestableHttpResponseCollectionProvider.php
rename to src/SingletonProvider/TestsHttpResponseCollectionProvider.php
index 021bb1c0a1c3004dafdb328a56070641edc7cdf4..46d4cba0a15b68a9c30b252d27a654d411953431 100644
--- a/src/SingletonProvider/TestableHttpResponseCollectionProvider.php
+++ b/src/SingletonProvider/TestsHttpResponseCollectionProvider.php
@@ -7,7 +7,7 @@ namespace Distantmagic\Resonance\SingletonProvider;
 use Distantmagic\Resonance\Attribute\RequiresSingletonCollection;
 use Distantmagic\Resonance\Attribute\RespondsWith;
 use Distantmagic\Resonance\Attribute\Singleton;
-use Distantmagic\Resonance\Attribute\TestableHttpResponse;
+use Distantmagic\Resonance\Attribute\TestsHttpResponse;
 use Distantmagic\Resonance\HttpResponderInterface;
 use Distantmagic\Resonance\PHPProjectFiles;
 use Distantmagic\Resonance\ReflectionClassAttributeManager;
@@ -15,20 +15,20 @@ use Distantmagic\Resonance\SingletonAttribute;
 use Distantmagic\Resonance\SingletonCollection;
 use Distantmagic\Resonance\SingletonContainer;
 use Distantmagic\Resonance\SingletonProvider;
-use Distantmagic\Resonance\TestableHttpResponseCollection;
+use Distantmagic\Resonance\TestsHttpResponseCollection;
 use LogicException;
 use ReflectionClass;
 
 /**
- * @template-extends SingletonProvider<TestableHttpResponseCollection>
+ * @template-extends SingletonProvider<TestsHttpResponseCollection>
  */
 #[RequiresSingletonCollection(SingletonCollection::HttpResponder)]
-#[Singleton(provides: TestableHttpResponseCollection::class)]
-final readonly class TestableHttpResponseCollectionProvider extends SingletonProvider
+#[Singleton(provides: TestsHttpResponseCollection::class)]
+final readonly class TestsHttpResponseCollectionProvider extends SingletonProvider
 {
-    public function provide(SingletonContainer $singletons, PHPProjectFiles $phpProjectFiles): TestableHttpResponseCollection
+    public function provide(SingletonContainer $singletons, PHPProjectFiles $phpProjectFiles): TestsHttpResponseCollection
     {
-        $testableHttpResponseCollection = new TestableHttpResponseCollection();
+        $testableHttpResponseCollection = new TestsHttpResponseCollection();
 
         foreach ($this->collectResponders($singletons) as $testableHttpResponseAttribute) {
             $reflectionClass = new ReflectionClass($testableHttpResponseAttribute->singleton);
@@ -57,14 +57,14 @@ final readonly class TestableHttpResponseCollectionProvider extends SingletonPro
     }
 
     /**
-     * @return iterable<SingletonAttribute<HttpResponderInterface,TestableHttpResponse>>
+     * @return iterable<SingletonAttribute<HttpResponderInterface,TestsHttpResponse>>
      */
     private function collectResponders(SingletonContainer $singletons): iterable
     {
         return $this->collectAttributes(
             $singletons,
             HttpResponderInterface::class,
-            TestableHttpResponse::class,
+            TestsHttpResponse::class,
         );
     }
 }
diff --git a/src/TestableHttpResponseCollection.php b/src/TestsHttpResponseCollection.php
similarity index 50%
rename from src/TestableHttpResponseCollection.php
rename to src/TestsHttpResponseCollection.php
index 21538558caf5cc32f0de84633c3ae7e90484d504..dd69732ae27a8424a9156bdea93dfbda00fd6b7e 100644
--- a/src/TestableHttpResponseCollection.php
+++ b/src/TestsHttpResponseCollection.php
@@ -5,44 +5,44 @@ declare(strict_types=1);
 namespace Distantmagic\Resonance;
 
 use Distantmagic\Resonance\Attribute\RespondsWith;
-use Distantmagic\Resonance\Attribute\TestableHttpResponse;
+use Distantmagic\Resonance\Attribute\TestsHttpResponse;
 use Ds\Map;
 use Ds\Set;
 
-readonly class TestableHttpResponseCollection
+readonly class TestsHttpResponseCollection
 {
     /**
-     * @var Map<HttpResponderInterface,Set<TestableHttpResponse>>
+     * @var Map<HttpResponderInterface,Set<TestsHttpResponse>>
      */
     public Map $httpResponder;
 
     /**
-     * @var Map<TestableHttpResponse,Map<int,RespondsWith>>
+     * @var Map<TestsHttpResponse,Map<int,RespondsWith>>
      */
-    public Map $testableHttpResponse;
+    public Map $testsHttpResponse;
 
     public function __construct()
     {
         $this->httpResponder = new Map();
-        $this->testableHttpResponse = new Map();
+        $this->testsHttpResponse = new Map();
     }
 
     public function registerTestableHttpResponse(
         HttpResponderInterface $httpResponder,
-        TestableHttpResponse $testableHttpResponse,
+        TestsHttpResponse $testsHttpResponse,
         RespondsWith $respondsWith,
     ): void {
         if (!$this->httpResponder->hasKey($httpResponder)) {
             $this->httpResponder->put($httpResponder, new Set());
         }
 
-        $this->httpResponder->get($httpResponder)->add($testableHttpResponse);
+        $this->httpResponder->get($httpResponder)->add($testsHttpResponse);
 
-        if (!$this->testableHttpResponse->hasKey($testableHttpResponse)) {
-            $this->testableHttpResponse->put($testableHttpResponse, new Map());
+        if (!$this->testsHttpResponse->hasKey($testsHttpResponse)) {
+            $this->testsHttpResponse->put($testsHttpResponse, new Map());
         }
 
-        $this->testableHttpResponse->get($testableHttpResponse)->put(
+        $this->testsHttpResponse->get($testsHttpResponse)->put(
             $respondsWith->status,
             $respondsWith,
         );