Friday, January 21, 2022

How to use multiple SMTP accounts in one TYPO3 installation

When TYPO3 is used to serve multiple websites in one installation, it may sometimes be required to configure multiple SMTP accounts in order to send emails from TYPO3 (e.g. mailforms or notifications) to different recipients. This may especially be important, when the recipient mailserver has a strict spam filter or when the domain uses a SPF, DKIM or DMARC and the mailserver only accepts emails from thrusted sources.

In TYPO3 you can configure one global SMTP server in LocalConfiguration.php by using the following settings:

$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport'] = 'smtp';
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_server'] = 'your.mailserver.tld';
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_encrypt'] = true;
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_username'] = 'username';
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_password'] = 'password';
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'] = 'email@your.mailserver.tld';

This setting however reflects to any hosted website in your TYPO3 installation and the email-server for typo3-website1.tld may possible not accept emails with a sender from the domain typo3-website2.tld.

In order to provide multiple SMTP servers for different websites in a TYPO3 installation, I configure different SMTP servers in AdditionalConfiguration.php 


if (($_SERVER['SERVER_NAME'] ?? '') === 'typo3-website1.tld') {
    $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_server'] = 'mail.typo3-website1.tld';
    $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_encrypt'] = true;
    $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_username'] = 'username';
    $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_password'] = 'password';
    $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'] = 'email@typo3-website1.tld';
}

if (($_SERVER['SERVER_NAME'] ?? '') === 'typo3-website2.tld') {
    $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_server'] = 'mail.typo3-website2.tld';
    $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_encrypt'] = true;
    $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_username'] = 'username';
    $GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_password'] = 'password';
    $GLOBALS['TYPO3_CONF_VARS']['MAIL']['defaultMailFromAddress'] = 'email@typo3-website2.tld';
}

Since AdditionalConfiguration.php is evaluated on every request, TYPO3 will conditionally use the email settings depending on the $_SERVER['SERVER_NAME'] variable.

Note, that this solution only applies to web requests and does not work in CLI context (e.g. scheduler task).

Wednesday, January 19, 2022

TYPO3 - Multiple dynamic parameters for a typolink using a custom userFunc

I often use the TYPO3 linkHandler to enable the possibility for editors to create direct links to records from within the CKEditor in TYPO3 backend. This is all well documented and easy to configure using the RecordLinkHandler, as long as the resulting link only contains one dynamic parameter. But sometimes it may be required to have multiple dynamic parameters for the resulting link. In this case you may need to create a userFunc for the typolink function in order to create a custom configuration which uses multiple dynamic parameters.

Requirement

Let us assume, you have an event which has multiple event registrations. Registrations are listed in the detail view of an event and each registration is shown as an accordion item with a unique ID in markup. Now you want to create a link to an event and set a link anchor to a specific registration. The resulting URL should be as shown below:

https://www.cool-events.tld/events/my-first-event#registration-1

Calling the URL will open the event detail page and scroll down the the HTML element with the ID "registration-1".

Note: This is just an example, which also can be achieved without a custom userFunc. Goal of this article is to demonstrate how to use a userFunc for typolink.

Solution

In order to archive the requirement, first a linkHandler Page TSConfig must be created as shown below:


TCEMAIN.linkHandler {
    event {
        handler = TYPO3\CMS\Recordlist\LinkHandler\RecordLinkHandler
        label = Event Registration
        configuration {
            table = tx_sfeventmgt_domain_model_registration
        }
    }
}

Next, the TypoScript for the link generation is added. 


config {
  recordLinks {
    registration {
      typolink {
        parameter = 1
        userFunc = DERHANSEN\SfEventMgt\UserFunc\TypoLink->createEventLink
        userFunc {
          eventUid = TEXT
          eventUid.data = field:event
          registrationUid = TEXT
          registrationUid.data = field:uid
        }
      }
    }
  }
}

Finally a custom userFunc needs to be created which renders the A-tag for the link.


<?php

declare(strict_types=1);

namespace DERHANSEN\SfEventMgt\UserFunc;

use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;

class TypoLink
{
    private const EVENT_DETAILPID = 22;

    public ContentObjectRenderer $cObj;

    public function createEventLink(array $content, array $config): string
    {
        $eventUid = $this->cObj->cObjGetSingle($config['eventUid'], $config['eventUid.']);
        $registrationUid = $this->cObj->cObjGetSingle($config['registrationUid'], $config['registrationUid.']);

        // Link parameters (can also contain multiple dynamic parameters)
        $parameters = [
            'tx_sfeventmgt_pieventdetail' => [
                'controller' => 'Event',
                'action' => 'detail',
                'event' => $eventUid,
            ]
        ];

        $link = $this->cObj->typoLink($this->cObj->lastTypoLinkResult->getLinkText(), [
            'parameter' => self::EVENT_DETAILPID,
            'additionalParams' => '&' . http_build_query($parameters),
            'section' => 'registration-' . $registrationUid,
            'returnLast' => 'url',
        ]);

        return '<a href="' . $link . '">';
    }
}

The most important part is, that the custom userFunc must only return the opening A-tag. In the userFunc, it is basically possible to construct the resulting link however you want. In the example above, 2 dynamic parameters are used in the function ($eventUid and $registrationUid). It is of course also possible to e.g. do dynamic database lookups in the function to fetch other dynamic parameters required for link construction.