diff --git a/module/VuFind/src/VuFind/Mailer/Mailer.php b/module/VuFind/src/VuFind/Mailer/Mailer.php
index dd61e501841392e1f2a51872c936f8b566be81eb..1d84e450eefef661cd9ca7a760ef728c8291f94a 100644
--- a/module/VuFind/src/VuFind/Mailer/Mailer.php
+++ b/module/VuFind/src/VuFind/Mailer/Mailer.php
@@ -32,6 +32,9 @@ use Laminas\Mail\AddressList;
 use Laminas\Mail\Header\ContentType;
 use Laminas\Mail\Message;
 use Laminas\Mail\Transport\TransportInterface;
+use Laminas\Mime\Message as MimeMessage;
+use Laminas\Mime\Mime;
+use Laminas\Mime\Part as MimePart;
 use VuFind\Exception\Mail as MailException;
 
 /**
@@ -89,17 +92,16 @@ class Mailer implements \VuFind\I18n\Translator\TranslatorAwareInterface
     }
 
     /**
-     * Get a blank email message object.
+     * Get a text email message object.
      *
      * @return Message
      */
     public function getNewMessage()
     {
-        $message = new Message();
-        $message->setEncoding('UTF-8');
+        $message = $this->getNewBlankMessage();
         $headers = $message->getHeaders();
         $ctype = new ContentType();
-        $ctype->setType('text/plain');
+        $ctype->setType(Mime::TYPE_TEXT);
         $ctype->addParameter('charset', 'UTF-8');
         $headers->addHeader($ctype);
         return $message;
@@ -120,6 +122,18 @@ class Mailer implements \VuFind\I18n\Translator\TranslatorAwareInterface
         return $this;
     }
 
+    /**
+     * Get a blank email message object.
+     *
+     * @return Message
+     */
+    public function getNewBlankMessage()
+    {
+        $message = new Message();
+        $message->setEncoding('UTF-8');
+        return $message;
+    }
+
     /**
      * Set the mail transport object.
      *
@@ -152,6 +166,47 @@ class Mailer implements \VuFind\I18n\Translator\TranslatorAwareInterface
         return $list;
     }
 
+    /**
+     * Constructs a {@see MimeMessage} body from given text and html content.
+     *
+     * @param string|null $text Mail content used for plain text part
+     * @param string|null $html Mail content used for html part
+     *
+     * @return MimeMessage
+     */
+    public function buildMultipartBody(
+        string $text = null,
+        string $html = null
+    ): MimeMessage {
+        $parts = new MimeMessage();
+
+        if ($text) {
+            $textPart = new MimePart($text);
+            $textPart->setType(Mime::TYPE_TEXT);
+            $textPart->setCharset('utf-8');
+            $textPart->setEncoding(Mime::ENCODING_QUOTEDPRINTABLE);
+            $parts->addPart($textPart);
+        }
+
+        if ($html) {
+            $htmlPart = new MimePart($html);
+            $htmlPart->setType(Mime::TYPE_HTML);
+            $htmlPart->setCharset('utf-8');
+            $htmlPart->setEncoding(Mime::ENCODING_QUOTEDPRINTABLE);
+            $parts->addPart($htmlPart);
+        }
+
+        $alternativePart = new MimePart($parts->generateMessage());
+        $alternativePart->setType('multipart/alternative');
+        $alternativePart->setBoundary($parts->getMime()->boundary());
+        $alternativePart->setCharset('utf-8');
+
+        $body = new MimeMessage();
+        $body->setParts([$alternativePart]);
+
+        return $body;
+    }
+
     /**
      * Send an email message.
      *
@@ -159,7 +214,7 @@ class Mailer implements \VuFind\I18n\Translator\TranslatorAwareInterface
      * delimited list)
      * @param string|Address             $from    Sender name and email address
      * @param string                     $subject Subject line for message
-     * @param string                     $body    Message body
+     * @param string|MimeMessage         $body    Message body
      * @param string                     $cc      CC recipient (null for none)
      * @param string|Address|AddressList $replyTo Reply-To address (or delimited
      * list, null for none)
@@ -220,8 +275,10 @@ class Mailer implements \VuFind\I18n\Translator\TranslatorAwareInterface
         // Convert all exceptions thrown by mailer into MailException objects:
         try {
             // Send message
-            $message = $this->getNewMessage()
-                ->addFrom($from)
+            $message = $body instanceof MimeMessage
+                ? $this->getNewBlankMessage()
+                : $this->getNewMessage();
+            $message->addFrom($from)
                 ->addTo($recipients)
                 ->setBody($body)
                 ->setSubject($subject);
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Mailer/MailerTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Mailer/MailerTest.php
index f79aba37c172a454b91271f850e03ebeff01e380..3d69b969e42ded319a96cf8db237f6d8988b5cbd 100644
--- a/module/VuFind/tests/unit-tests/src/VuFindTest/Mailer/MailerTest.php
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Mailer/MailerTest.php
@@ -426,6 +426,33 @@ class MailerTest extends \VuFindTest\Unit\TestCase
         $mailer = new Mailer($transport);
         $mailer->resetConnection();
     }
+
+    /**
+     * Test sending an email using with text part and html part and multipart content type.
+     *
+     * @return void
+     * @throws \VuFind\Exception\Mail
+     */
+    public function testSendMimeMessageWithMultipartAlternativeContentType()
+    {
+        $this->html = '<!DOCTYPE html><head><title>html</title></head><body>html body part</body></html>';
+        $this->text = 'this is the text part';
+        $callback = function ($message) {
+            $fromString = $message->getFrom()->current()->toString();
+            return '<to@example.com>' == $message->getTo()->current()->toString()
+                && 'Sender TextName <from@example.com>' == $fromString
+                && 'subject' == $message->getSubject()
+                && 0 <= strpos($message->getBody()->getParts()[0]->getContent(), $this->html)
+                && 0 <= strpos($message->getBody()->getParts()[0]->getContent(), $this->text)
+                && 'multipart/alternative' == $message->getHeaders()->get('Content-Type')->getType();
+        };
+        $transport = $this->createMock(\Laminas\Mail\Transport\TransportInterface::class);
+        $transport->expects($this->once())->method('send')->with($this->callback($callback));
+        $address = new Address('from@example.com', 'Sender TextName');
+        $mailer = new Mailer($transport);
+        $body = $mailer->buildMultipartBody($this->text, $this->html);
+        $mailer->send('to@example.com', $address, 'subject', $body);
+    }
 }
 
 class MockEmailRenderer extends \Laminas\View\Renderer\PhpRenderer