diff --git a/lib/AppInfo/BootstrapSingleton.php b/lib/AppInfo/BootstrapSingleton.php
index 3d838e2c876e0753ce268e040a36abb6f19cba62..cf0afa67d3a5d7c57e035f10c144a4bb68172973 100644
--- a/lib/AppInfo/BootstrapSingleton.php
+++ b/lib/AppInfo/BootstrapSingleton.php
@@ -40,6 +40,7 @@ use OCA\Mail\Listener\AddressCollectionListener;
 use OCA\Mail\Listener\DeleteDraftListener;
 use OCA\Mail\Listener\DraftMailboxCreatorListener;
 use OCA\Mail\Listener\FlagRepliedMessageListener;
+use OCA\Mail\Listener\InteractionListener;
 use OCA\Mail\Listener\MessageDeletedCacheUpdaterListener;
 use OCA\Mail\Listener\SaveSentMessageListener;
 use OCA\Mail\Listener\TrashMailboxCreatorListener;
@@ -128,6 +129,7 @@ class BootstrapSingleton {
 		$dispatcher->addServiceListener(MessageSentEvent::class, AddressCollectionListener::class);
 		$dispatcher->addServiceListener(MessageSentEvent::class, DeleteDraftListener::class);
 		$dispatcher->addServiceListener(MessageSentEvent::class, FlagRepliedMessageListener::class);
+		$dispatcher->addServiceListener(MessageSentEvent::class, InteractionListener::class);
 		$dispatcher->addServiceListener(MessageSentEvent::class, SaveSentMessageListener::class);
 		$dispatcher->addServiceListener(SaveDraftEvent::class, DraftMailboxCreatorListener::class);
 	}
diff --git a/lib/Events/MessageSentEvent.php b/lib/Events/MessageSentEvent.php
index 9d132bdbdce49d744977ecaa0b5f9b2045d6b83f..c0642e68a8151334940af18a09e570ba83f04ed4 100644
--- a/lib/Events/MessageSentEvent.php
+++ b/lib/Events/MessageSentEvent.php
@@ -53,7 +53,7 @@ class MessageSentEvent extends Event {
 	public function __construct(Account $account,
 								NewMessageData $newMessageData,
 								?RepliedMessageData $repliedMessageData,
-								?int $draftUid = null,
+								?int $draftUid,
 								IMessage $message,
 								Horde_Mime_Mail $mail) {
 		parent::__construct();
diff --git a/lib/Listener/InteractionListener.php b/lib/Listener/InteractionListener.php
new file mode 100644
index 0000000000000000000000000000000000000000..ce48b5635a46780ad5bd7c92afeb9cf52e1436a6
--- /dev/null
+++ b/lib/Listener/InteractionListener.php
@@ -0,0 +1,88 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCA\Mail\Listener;
+
+use OCA\Mail\Address;
+use OCA\Mail\Events\MessageSentEvent;
+use OCP\Contacts\Events\ContactInteractedWithEvent;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\EventDispatcher\IEventListener;
+use OCP\ILogger;
+use OCP\IUserSession;
+use function class_exists;
+
+class InteractionListener implements IEventListener {
+
+	/** @var IEventDispatcher */
+	private $dispatcher;
+
+	/** @var IUserSession */
+	private $userSession;
+
+	/** @var ILogger */
+	private $logger;
+
+	public function __construct(IEventDispatcher $dispatcher,
+								IUserSession $userSession,
+								ILogger $logger) {
+		$this->dispatcher = $dispatcher;
+		$this->userSession = $userSession;
+		$this->logger = $logger;
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	public function handle(Event $event): void {
+		if (!($event instanceof MessageSentEvent)) {
+			return;
+		}
+		if (!class_exists(ContactInteractedWithEvent::class)) {
+			$this->logger->debug(ContactInteractedWithEvent::class . ' does not exist, ignoring the event');
+			return;
+		}
+		if (($user = $this->userSession->getUser()) === null) {
+			$this->logger->debug('no user object found');
+			return;
+		}
+		$recipients = $event->getMessage()->getTo()
+			->merge($event->getMessage()->getCC())
+			->merge($event->getMessage()->getBCC());
+		foreach ($recipients->iterate() as $recipient) {
+			/** @var Address $recipient */
+			$interactionEvent = new ContactInteractedWithEvent($user);
+			$email = $recipient->getEmail();
+			if ($email === null) {
+				// Weird, bot ok
+				continue;
+			}
+			$interactionEvent->setEmail($email);
+			$this->dispatcher->dispatch(ContactInteractedWithEvent::class, $interactionEvent);
+		}
+	}
+
+}
diff --git a/tests/Unit/Listener/InteractionListenerTest.php b/tests/Unit/Listener/InteractionListenerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..fa8ccb88111718db94701300911898bc504a0c55
--- /dev/null
+++ b/tests/Unit/Listener/InteractionListenerTest.php
@@ -0,0 +1,106 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @author 2020 Christoph Wurst <christoph@winzerhof-wurst.at>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace OCA\Mail\Tests\Unit\Listener;
+
+use ChristophWurst\Nextcloud\Testing\ServiceMockObject;
+use ChristophWurst\Nextcloud\Testing\TestCase;
+use OCA\Mail\Address;
+use OCA\Mail\AddressList;
+use OCA\Mail\Events\MessageSentEvent;
+use OCA\Mail\Listener\InteractionListener;
+use OCA\Mail\Model\IMessage;
+use OCP\Contacts\Events\ContactInteractedWithEvent;
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+use function class_exists;
+
+class InteractionListenerTest extends TestCase {
+
+	/** @var ServiceMockObject */
+	private $serviceMock;
+
+	/** @var InteractionListener */
+	private $listener;
+
+	protected function setUp(): void {
+		parent::setUp();
+
+		$this->serviceMock = $this->createServiceMock(InteractionListener::class);
+
+		$this->listener = $this->serviceMock->getService();
+	}
+
+	public function testHandleUnrelated(): void {
+		$event = new Event();
+
+		$this->listener->handle($event);
+
+		$this->addToAssertionCount(1);
+	}
+
+	public function testHandle(): void {
+		if (!class_exists(ContactInteractedWithEvent::class)) {
+			$this->markTestSkipped(ContactInteractedWithEvent::class . ' does not exist');
+			return;
+		}
+
+		$to = new AddressList([
+			new Address('rec 1', 'u1@domain.tld'),
+			new Address('rec 1', 'u2@domain.tld'),
+		]);
+		$cc = new AddressList([
+			new Address('rec 1', 'u3@domain.tld'),
+		]);
+		$bcc = new AddressList([
+			new Address('rec 1', 'u4@domain.tld'),
+			new Address('rec 1', 'u2@domain.tld'), // intentional duplicate
+		]);
+		$event = $this->createMock(MessageSentEvent::class);
+		$message = $this->createMock(IMessage::class);
+		$event
+			->method('getMessage')
+			->willReturn($message);
+		$message
+			->method('getTo')
+			->willReturn($to);
+		$message
+			->method('getCC')
+			->willReturn($cc);
+		$message
+			->method('getBCC')
+			->willReturn($bcc);
+		$user = $this->createMock(IUser::class);
+		$this->serviceMock->getParameter('userSession')
+			->method('getUser')
+			->willReturn($user);
+		$this->serviceMock->getParameter('dispatcher')
+			->expects($this->exactly(4))
+			->method('dispatch');
+
+		$this->listener->handle($event);
+	}
+
+}