diff --git a/src/quick/CMakeLists.txt b/src/quick/CMakeLists.txt
index e26b528..4ba510f 100644
--- a/src/quick/CMakeLists.txt
+++ b/src/quick/CMakeLists.txt
@@ -1,38 +1,39 @@
 # SPDX-FileCopyrightText: 2023 Carl Schwan <carl.schwan@gnupg.com>
 # SPDX-License-Identifier: BSD-3-Clause
 
-ecm_add_qml_module(mimetreeparser_plugin URI "org.kde.pim.mimetreeparser" VERSION 1.0)
+ecm_add_qml_module(mimetreeparser_plugin
+    URI "org.kde.pim.mimetreeparser"
+    VERSION 1.0
+    GENERATE_PLUGIN_SOURCE
+    DEPENDENCIES QtQuick
+)
 
 target_sources(mimetreeparser_plugin PRIVATE
-    mimetreeparserplugin.cpp
-    mimetreeparserplugin.h
+    types.h
 )
 
 target_link_libraries(mimetreeparser_plugin PRIVATE
-    Qt::Quick
-    KPim6::MimeTreeParserCore Gpgmepp
+    Qt6::Qml
+    KPim6::MimeTreeParserCore
 )
 
 ecm_target_qml_sources(mimetreeparser_plugin
     SOURCES
         qml/MailViewer.qml
 )
 
 ecm_target_qml_sources(mimetreeparser_plugin PRIVATE
     PATH private
     SOURCES
-    qml/private/AttachmentDelegate.qml
-    qml/private/Banner.qml
-    qml/private/ErrorPart.qml
-    qml/private/HtmlPart.qml
-    qml/private/ICalPart.qml
-    qml/private/MailPart.qml
-    qml/private/MailPartModel.qml
-    qml/private/MailPartView.qml
-    qml/private/TextPart.qml
+        qml/private/AttachmentDelegate.qml
+        qml/private/Banner.qml
+        qml/private/ErrorPart.qml
+        qml/private/HtmlPart.qml
+        qml/private/ICalPart.qml
+        qml/private/MailPart.qml
+        qml/private/MailPartModel.qml
+        qml/private/MailPartView.qml
+        qml/private/TextPart.qml
 )
 
-ecm_finalize_qml_module(mimetreeparser_plugin
-    DESTINATION ${KDE_INSTALL_QMLDIR}
-    BUILD_SHARED_LIBS OFF
-)
+ecm_finalize_qml_module(mimetreeparser_plugin DESTINATION ${KDE_INSTALL_QMLDIR})
diff --git a/src/quick/mimetreeparserplugin.cpp b/src/quick/mimetreeparserplugin.cpp
deleted file mode 100644
index 02222c4..0000000
--- a/src/quick/mimetreeparserplugin.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
-// SPDX-License-Identifier: LGPL-2.0-or-later
-
-#include "mimetreeparserplugin.h"
-
-#include <MimeTreeParserCore/AttachmentModel>
-#include <MimeTreeParserCore/MessageParser>
-#include <MimeTreeParserCore/PartModel>
-#include <QQmlEngine>
-
-void MimeTreeParserPlugin::registerTypes(const char *uri)
-{
-    Q_ASSERT(uri == QByteArray("org.kde.pim.mimetreeparser"));
-
-    qmlRegisterModule(uri, 1, 0);
-    qmlRegisterType<MessageParser>(uri, 1, 0, "MessageParser");
-    qRegisterMetaType<PartModel::Types>("PartModel::Types");
-    qmlRegisterUncreatableType<PartModel>(uri, 1, 0, "PartModel", QStringLiteral("not instanciated"));
-    qmlRegisterUncreatableType<AttachmentModel>(uri, 1, 0, "AttachmentModel", QStringLiteral("not instanciated"));
-}
-
-#include "moc_mimetreeparserplugin.cpp"
diff --git a/src/quick/mimetreeparserplugin.h b/src/quick/mimetreeparserplugin.h
deleted file mode 100644
index 0d1e798..0000000
--- a/src/quick/mimetreeparserplugin.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// SPDX-FileCopyrightText: 2022 Carl Schwan <carl@carlschwan.eu>
-// SPDX-License-Identifier: LGPL-2.0-or-later
-
-#pragma once
-
-#include <QQmlExtensionPlugin>
-
-class MimeTreeParserPlugin : public QQmlExtensionPlugin
-{
-    Q_OBJECT
-    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
-
-public:
-    void registerTypes(const char *uri) override;
-};
diff --git a/src/quick/qml/private/MailPartView.qml b/src/quick/qml/private/MailPartView.qml
index d76ad30..8c26ad0 100644
--- a/src/quick/qml/private/MailPartView.qml
+++ b/src/quick/qml/private/MailPartView.qml
@@ -1,44 +1,44 @@
 // SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
 // SPDX-FileCopyrightText: 2016 Michael Bohlender <michael.bohlender@kdemail.net>
 // SPDX-License-Identifier: GPL-2.0-or-later
 
-import QtQuick 2.15
-import QtQuick.Layouts 1.15
-import org.kde.kirigami 2.14 as Kirigami
-import org.kde.pim.mimetreeparser 1.0
+import QtQuick
+import QtQuick.Layouts
+import org.kde.kirigami as Kirigami
+import org.kde.pim.mimetreeparser
 
 ListView {
     id: root
 
     property alias message: messageParser.message
     readonly property string subject: messageParser.subject
     readonly property string from: messageParser.from
     readonly property string sender: messageParser.sender
     readonly property string to: messageParser.to
     readonly property string cc: messageParser.cc
     readonly property string bcc: messageParser.bcc
     readonly property date dateTime: messageParser.date
 
     property alias rootIndex: visualModel.rootIndex
     property alias padding: visualModel.padding
     property alias searchString: visualModel.searchString
     property alias autoLoadImages: visualModel.autoLoadImages
     property var attachmentModel: messageParser.attachments
 
     property url icalCustomComponent
 
     topMargin: padding
     bottomMargin: padding
 
     spacing: Kirigami.Units.smallSpacing
 
     model: MailPartModel {
         id: visualModel
         model: messageParser.parts
         icalCustomComponent: root.icalCustomComponent
     }
 
     MessageParser {
         id: messageParser
     }
 }
diff --git a/src/quick/types.h b/src/quick/types.h
new file mode 100644
index 0000000..b78088e
--- /dev/null
+++ b/src/quick/types.h
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: 2024 Carl Schwan <carl@carlschwan.eu>
+// SPDX-License-Identifier: LGPL-3.0-or-later
+
+#include <MimeTreeParserCore/AttachmentModel>
+#include <MimeTreeParserCore/MessageParser>
+#include <MimeTreeParserCore/PartModel>
+
+#include <QtQml/qqmlregistration.h>
+
+class MessageParserForeign : public QObject
+{
+    Q_OBJECT
+    QML_NAMED_ELEMENT(MessageParser)
+    QML_FOREIGN(MessageParser)
+};
+
+class PartModelForeign : public QObject
+{
+    Q_OBJECT
+    QML_NAMED_ELEMENT(PartModel)
+    QML_UNCREATABLE("Enum only")
+    QML_FOREIGN(PartModel)
+};
+
+class AttachmentModelForeign : public QObject
+{
+    Q_OBJECT
+    QML_NAMED_ELEMENT(AttachmentModel)
+    QML_UNCREATABLE("Enum only")
+    QML_FOREIGN(AttachmentModel)
+};