I've updated the information below to work with Craft 3.7

I wanted to allow people to chose which person/department to send a message to using the P&T Contact Form plugin. I've seen one method to do this, eg:

    <select name="toEmail">
          <option value="{{ '[email protected]'|hash }}">1st name</option>
          <option value="{{ '[email protected]'|hash }}">2nd name</option>

but it does mean that the actual email address is visible in the HTML code. Which would allow the spam robots to harvest it. Although it may be that the hash added makes it harder?

In the ideal world I would like the address to be completely hidden or encrypted in the form page html. I wondered if the name="toEmail" value=" " could be a variable that is passed along with the value="contactForm/sendMessage" action, that could then be referenced and replaced from a list in the contact form config file.

It seems to me that not having plain text email addresses should be the standard way of working so I'm surprised that there isn't already a plugin or method to do this, but I couldn't find one.

Edit to show the final solution I'm using.

I'm very grateful to Robin Schambach, who provided all the clever code, I've just put it all together here to help anyone looking for a similar solution. The email addresses are never available or visible on the front end.

I created a Section named Contacts with plain text data fields of:




contactKey (this stores the name in camelCase, so "johnSmith" not "John Smith") I use the preparse plugin to auto generate this.

This allows the end user to maintain/update the names and addresses of contacts without the developer needing to make changes on the server.

Install P&T Contact form plugin and add a config file to overide the plugin settings. The contents of that file should be:

$request = Craft::$app->request;
if (!$request->getIsConsoleRequest()) {
    $toEmailId = $request->getBodyParam('toEmail');
    // the rest of the configuration code goes here

$criteria = \craft\elements\Entry::find()

$allAddresses = [];
foreach($criteria as $entry){
    $allAddresses[$entry->contactKey] = $entry->contactEmail;
$toEmail = (array_key_exists($toEmailId, $allAddresses))? $allAddresses[$toEmailId] : null;
return [
    'toEmail' => ($toEmail ?: null),
    'prependSubject'      => '',
    'prependSender'       => 'From website:',
    'allowAttachments'    => false,
    'successFlashMessage' => 'Thanks for your message'

On my contacts page that lists all the possible contacts, the submit to the contact form passes the id of the entry:

<input type="hidden" name="id" value="{{ entry.id }}">

In the contact form template I get that entry:

{% set entry = craft.entries.id(craft.app.request.getBodyParam('id')).one() %}

Which enables you to be able to show/confirm the contact name/details of who the form will send to and get access to the contactKey.

<p><strong>You are sending this message to:</strong><br>
{{ entry.contactName }}, {{ entry.contactPosition }}</strong></p>

The contact form template is based on the P&T example. With the addition of this line to allow "Dynamically adding email recipients", as detailed on the P&T example.

<input type="hidden" name="toEmail" value="{{ entry.contactKey }}">

I had problems updating the original method to work with Craft 3.7 and am grateful for the help of MoritzLost in this thread to get it working again.

1 Answer 1


You can Create a custom array in which you store all valid email addresses and send the id which email to use

<select name="toEmail">
  <option value="1">1st name</option>
  <option value="2">2nd name</option>

and in your config file

namespace Craft;

$toEmailId = craft()->request->getPost('toEmail');
$yourArray = [
    1 => 'firstmail.com',
    2 => 'secondmail.com',
$toEmail = (array_key_exists($toEmailId, $yourArray))? $yourArray[$toEmailId]  : null;
return array(
    'toEmail' => $toEmail,
  • I've tried various combinations but I can't work out where to add your bit of backend code into my config file, which looks like this: <?php namespace Craft; $toEmail = craft()->request->getPost('toEmail'); return array( 'toEmail' => ($toEmail ?: null), 'prependSubject' => 'From website: ', ); I've tried every permutation I can think of.
    – Paul Frost
    Commented Dec 19, 2017 at 14:35
  • Ah, we are back to my limited programming skills again. I've looked at the ContactFormController in the P&T plugin but can't see anything like your code that I can edit. I had hoped there would be a simple plugin to solve what seemed like a common function on a website. But I should know by now that things I think of as normal everyday requirements are unusual and require programming skills outside of html & css.
    – Paul Frost
    Commented Dec 19, 2017 at 15:06
  • I edited my answer, it is untested but I thing that should work. I thing this approach might be easier for you. A custom controller/service would have been a little bit better but that works as well Commented Dec 19, 2017 at 15:07
  • Initial testing is working, so thanks for that, you have bailed me out again. Now I'll try and understand what's going on in that code.
    – Paul Frost
    Commented Dec 19, 2017 at 15:18
  • It's actually pretty easy. $toEmailId is the value / the id the requests sends. $yourArray is a simple array map, so a simple pair of key => emails depending which key the user selects in the frontend the array "converts" it to an email address and returns this value to the service. Depending on how you create your select you can change the $yourArray as well. So when you have a set of global configs, you can check this as well. Commented Dec 19, 2017 at 15:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.