Non-Unique Conditional Email Addresses with Webform.Module
I recently ran into two problems when using the "conditional recipients" functionality of the Drupal Webform module - recipient addresses must be unique, and addresses are exposed in the page markup. My solution involved creating mail "aliases" via hook_mail_alter().
The Webform module's conditional recipients feature is a flexible function that allows the values of a select box to be tied to email notification recipient addresses. A simple example for dropdown field such as "I need help with" could have the following options:
orders@example.com|Orders
customer_service@example.com|Customer Service
technical_support@example.com|Technical SupportBy selecting this "I need help with" select box under "Conditional e-mail recipients" form configuration, Webform will send a confirmation message to the appropriate address based on the option selected by the user. You can read more about Webform's conditional recipients on Drupal.org. However, there are two basic problems with this functionality.
- While the email addresses are not formatted as mailto: links, they are exposed in the form markup, which could lead to them being harvested by SPAM bots.
- The addresses must be unique. If in our example above, Customer Service and Technical Support both went to "support@example.com", only one of them would actually appear on the form. Keys must be unique when entering key/value pairs for Webform select fields. For example, the following will only display "Orders" and "Technical Support":
orders@example.com|Orders
support@example.com|Customer Service
support@example.com|Technical Support
Happily, there is a (fairly) simple solution that fixes both problems -- use hook_mail_alter() to set up mail aliases for the site. I generally create a "sitename_overrides" module for all of my sites as a place to put simple hook implementations, block implementations, etc. However, the following two functions could be added to a new module if necessary. For help setting up a new module, see the module developer's handbook.
Step 1: Create a function to generate an array of aliases and replacements (this must be placed inside a module -- "sitename_overrides.module" in this example):
<?php
/**
* Private method to define email address aliases.
*
* Returns a two-dimensional array: $aliases['search'] and $aliases['replace']
* meant for calls to str_replace().
*/
function _sitename_overrides_mail_aliases() {
$aliases = array();
/* User aliases. */
$aliases['search'][] = 'orders_at_example';
$aliases['replace'][] = 'orders@example.com';
$aliases['search'][] = 'customer_service_at_example';
$aliases['replace'][] = 'support@example.com';
$aliases['search'][] = 'technical_support_at_example';
$aliases['replace'][] = 'support@example.com';
return $aliases;
}
?>Step 2: Implement the mail_alter() hook for our mythical "sitename_overrides" module to replace our aliases with actual email addresses:
<?php
/**
* Implementation of hook_mail_alter().
*/
function sitename_overrides_mail_alter(&$message) {
/* Replace to: aliases defined in _modulename_mail_aliases(). */
$aliases = _modulename_mail_aliases();
$message['to'] = str_replace($aliases['search'],$aliases['replace'],$message['to']);
}
?>Step 3: Add or update the select field in the Webform with the aliases defined in step 1. So from our example:
orders_at_example|Orders
customer_service_at_example|Customer Service
technical_support_at_example|Technical SupportNow when Webform calls drupal_mail() to deliver your messages, the aliases will be turned into actual addresses, and can be delivered properly, all without exposing your email addresses online!
Comments
#1 alternative
Submitted by Visitor on Tue, 03/03/2009 - 07:03.
why dont you just use the additional processing? eg:
<?phpif ($form_values['submitted_tree']['subject']=="orders_at_example") {
$node->webform['additional_emails'][] = "orders@example.com";
}
?>
etc..
or am i missing something? (just started using webforms)
Timothy : www.spiraleye.com
#2 Interesting Method
Submitted by Eric Weik on Sun, 03/08/2009 - 21:15.
Timothy,
The additional-processing method seems like a great idea. For the particular application I was working on there was actually a long list of possible addresses and multiple forms, so a more centralized approach made sense. But for a single contact form, using the additional-processing method looks great because it wouldn't involve module development.
Thanks for the tip!
-Eric
#3 Thanks loads to both of you
Submitted by Will (not verified) on Mon, 02/01/2010 - 07:34.
Thanks loads to both of you for posting this information. It has helped me out massively.
One thing that confused me for a while was that in my example I was using multi select check boxes. It seems that in this case webform puts an additional form value into the mix. In my example I had to use the following code to get this working:
<?phpif ($form_values['submitted_tree']['webform_component_name']['webform_component_key']=="webform_component_key") {
$node->webform['additional_emails'][] = "orders@example.com";
}
?>
Where webform_component_name is the name you've given to the specific webform checkbox element, and webform_component_key is what you've named that option's key.
Just thought I'd post this for any other beginners like me, hopefully it'll save you the 2 hours I've just spent working this out! :)
Thanks again
#4 Devel.module and dpm() are great!
Submitted by Eric Weik on Mon, 02/01/2010 - 13:07.
Thanks for posting this tip Will!
I find that one of the single most useful tools for Drupal development is the dpm() function provided by the Devel module.
If you cannot figure out where that variable is that you need, if you have devel module installed, you can simply add the following to your code:
<?phpdpm($form_values);
?>
It will output a clickable hierarchy of values defined in the $form_values variable.
If you don't have any idea what variable you are even looking for, then you can try this:
<?phpdpm(get_defined_vars());
?>
For more information see the following:
#5 Great, many thanks. Will
Submitted by Will (not verified) on Thu, 02/04/2010 - 07:30.
Great, many thanks. Will definitely look into. It's one of those modules I've heard mentioned a lot but never looked into fully. Once I've got time I want to have a proper explore of Drupal under the hood so this sounds perfect.
In this instance I found out the variable by looking at the source code being outputted with Firebug.
By the way the switch code for multiple email addresses you posted below definitely does work. Just implemented and tested it with what I'm doing.
Thanks again, you're very much bookmarked!
#6 This is interesting. Thanks
Submitted by Visitor on Wed, 07/29/2009 - 11:03.
This is interesting. Thanks for posting about it. I don't really understand all of these terms and stuff, but it's good to learn new things.
#7 Seems a litle dificult to do,
Submitted by Visitor on Sat, 08/08/2009 - 00:42.
Seems a litle dificult to do, im new to drupal and made me difficultto understand completely, but your guide is so complete and detailed, i will try it, hope dont messed up the things.
Thanks for your info.
#8 additional-processing method
Submitted by Visitor (not verified) on Tue, 01/12/2010 - 16:12.
Hey there, coming to this thread very late, but I am curious how you would implement your idea the way "Timothy" did using additional processing. His example only swaps out one email address. How would you do it with more than one?
Thanks!
Paul
#9 Additional processing with multiple addresses
Submitted by Eric Weik on Sun, 01/17/2010 - 11:54.
Hi Paul,
I've not actually tried this, but I think the syntax to extend Timothy's example to add recipients based on the subject would look something like this:
<?phpswitch ($form_values['submitted_tree']['subject']) {
case "orders_at_example":
// Add two different CC address for "orders_at_example"
$node->webform['additional_emails'][] = "orders@example.com";
$node->webform['additional_emails'][] = "fulfillment@otherexample.com";
break;
case "info_at_example":
$node->webform['additional_emails'][] = "info@example.com";
break;
case "support_at_example":
$node->webform['additional_emails'][] = "support@example.com";
break;
}
?>
-Eric
#10 looks very useful
Submitted by Paul (not verified) on Sun, 01/17/2010 - 12:09.
Hi Eric,
That actually looks very useful. I may try that. Cheer!
Paul
#11 Would there be a way to
Submitted by Will (not verified) on Fri, 02/05/2010 - 06:29.
Would there be a way to specify an email address to send to if no fields are selected? I've been trying to figure it out but can't get it working.
#12 Default
Submitted by Eric Weik on Fri, 02/05/2010 - 08:49.
Will, have you tried simply adding a default case to the switch statement?
Updating the above example, it should look something like this:
<?phpswitch ($form_values['submitted_tree']['subject']) {
case "orders_at_example":
// Add two different CC address for "orders_at_example"
$node->webform['additional_emails'][] = "orders@example.com";
$node->webform['additional_emails'][] = "fulfillment@otherexample.com";
break;
case "info_at_example":
$node->webform['additional_emails'][] = "info@example.com";
break;
case "support_at_example":
$node->webform['additional_emails'][] = "support@example.com";
break;
default:
$node->webform['additional_emails'][] = "contact@example.com";
}
?>
#13 How rude of me, I didn't
Submitted by Will (not verified) on Wed, 02/24/2010 - 12:22.
How rude of me, I didn't notice you posted this. Sorry for not replying. Many thanks once again. I ended up just putting an 'other' option and making it a required field as we were in a hurry to get the site out on time (which we did, hooray). Now I've got a bit of breathing space I'll have a proper look over this at some point, as it seems a much more elegant solution.
All the best - Will
#14 This is genius! Great work!
Submitted by Chris Free (not verified) on Tue, 02/02/2010 - 17:11.
This is genius! Great work!
#15 reducing the number of emails
Submitted by Visitor (not verified) on Wed, 02/10/2010 - 14:22.
I have a form which I have created individual emails for each topic and piped them.
me@here.com|apples
you@here.com|pears
us@here.com|oranges
them@here.com|grapes
In those groups say me, us and them recieve the email. I don't want to receive 3 emails but I do want to know that apples, oranges and grapes were checked.
How can add additional php code that does some sorting to reduce the email output to one email?
#16 Default Behavior
Submitted by Eric Weik on Thu, 02/25/2010 - 00:00.
I'm not 100% sure I understand your question, but I believe what you are looking for is the default behavior of the Webform module.
If you add a "topic" field as outlined above and check "e-mail a submission copy" and "include in e-mails" for that field, a copy will be sent to each to the appropriate address(es), and the email will also show which options were checked.
#17 Thanks for all the
Submitted by Moz_D (not verified) on Wed, 02/24/2010 - 08:47.
Thanks for all the interesting help. I'm quite new to all of this and I'd really like to include this on my site, but I still have a problem. For some reason I keep getting an error:
warning: mail() [function.mail]: SMTP server response: 501 : recipient address must contain a domain in C:\Program_Files\wamp\www\includes\mail.inc on line 193.
It appears that the first part "hotmail_at_lr" isn't recognised in:
hotmail_at_lr|Orders
customer_service_at_example|Customer Service
technical_support_at_example|Technical Support
It only works when the first part is a real email address. But I'd really like the email address to be hidden and use the methods you've described. Can anyone suggest why this is happening ?
#18 Replacement isn't working
Submitted by Eric Weik on Wed, 02/24/2010 - 09:48.
Moz_D - It looks like "hotmail_at_lr" isn't being replaced with an actual e-mail address. Which of the methods discussed above are you using (e.g. the "write a module" method from the original blog post, or the "use additional processing" method discussed in the comments)?
#19 I first tried the module
Submitted by Moz_D (not verified) on Wed, 02/24/2010 - 11:17.
I first tried the module approach (with .info and .module files) and then I tried the additional processing. I also tried putting the code in the Additional Validation section without any luck. I really appreciate your help.
#20 Field identifiers, dpm, etc.
Submitted by Eric Weik on Wed, 02/24/2010 - 11:37.
If you only need to add aliases for a single form, the "additional processing" model is probably better (I originally developed my solution as a module because there were lots of forms on the site and it seemed like a good idea to have e-mail aliasing for the entire site).
So that said, probably the easiest place to make a mistake is in the field identifier / hash index when pulling the value out of the $form_values[] hash. E.g. in #9 above it is pulling from a hypothetical "subject" field with:
$form_values['submitted_tree']['subject']
I usually put "dpm($form_values);" at the top of my code to make sure I'm using the right identifier for the form field (like "subject" above). This only works if you have the devel.module installed though.
The other thing to check is that since you are using additional processing to add recipients, you do not need to specify your conditional field in "Conditional e-mail recipients" section of the form configuration (you did with the "module method", but not the "additional processing" method).
This is probably a little confusing since the "additional processing" method has been developed entirely in this comment thread. Perhaps I should make a new post outlining it in detail.
Hope this helps!
#21 Thank you once again for your
Submitted by Moz_D (not verified) on Wed, 02/24/2010 - 16:25.
Thank you once again for your help. I think you're right and I should be going for the simpler solution of "additional processing" rather than a module.
I've unselected everything in "Conditional e-mail recipients" (I only had "subject" selected) and I've taken away the email address in Configuration under "Webform mail settings" "E-mail to address:". I have the devel.module installed.
However I still can't seem to get the first part ("hotmail_at_lr") converted into an email address. When I look at the output from "dpm($form_values);", I get:
submitted (Array, 6 elements)
11 (String, 13 characters ) hotmail_at_lr
and:
details (Array, 4 elements)
email_subject (String, 2 characters ) 11
and further down the list:
submitted_tree (Array, 1 element)
email_us (Array, 6 elements)
subject (String, 13 characters ) hotmail_at_lr
I'm afraid I don't really understand the "field identifier / hash index", but I think that the above output tells me that the field is correctly called "subject" and that I'm getting the right "subject" value as shown under "submitted_tree". But I can't see the email address that I want anywhere in this devel output. What should it be under ? I'm also not sure why "email_subject" is "11".
I've also made sure that php is selected in the Input Format just in case it's not recognising this php code that I've put in "Additional Processing" under "Webform advanced settings". And I've tried all the different combinations of the php code from #1 to #12 above. It's as if the php code isn't working. Strange.
Any ideas ?
Many many thanks once again.
#22 Puzzling
Submitted by Eric Weik on Wed, 02/24/2010 - 23:29.
Moz - The output from dpm($form_values) is just to double-check that you are using the right identifier to access the submitted field value. And based on what you've written above, it looks like $form_values['submitted_tree']['subject'] should correct for your form. In which case the code from #9 or #12 should also work. Without seeing your setup, I'm at a loss to explain why it doesn't work.
#23 One possibility...
Submitted by Eric Weik on Wed, 02/24/2010 - 23:48.
Moz - I just set up a test form to make sure this does indeed work as expected, and it worked for me with drupal-6.15 and webform-6.x-2.9.
Two things I thought of while setting up the form:
1) Make sure that your "subject" field does NOT have "email a submission copy" checked. This would try to send the email directly with the submitted value of "hotmail_at_lr". Instead, we're using it to add recipients with "additional processing" code.
2) The sample code from #1, #9, or #12 will not work if have have marked your "subject" field as "Multiple". If it is marked "multiple", then $form_values['submitted_tree']['subject'] will be a list of selected options instead of a string.
#24 What now? Code re-write!
Submitted by tscad (not verified) on Sun, 03/28/2010 - 15:51.
I might just be wishing for a miracle here but here goes. With 3x Beta 2 out and still no conditional recipients option what are we to do? It appears as if 'additional_emails' has been removed and is no longer an option. I like the functionality and ease of use of 3x, but they are still way behind the times with leaving emails visible in the source code. Anyone have any ideas of how to simply search and replace the select key with an email? Or is 'additional_emails' re-written so that I can't find it?
#25 Ill News
Submitted by Eric Weik on Mon, 03/29/2010 - 15:28.
I've not tried the betas yet. Some of the new features look really useful (I could have used "conditional logic in multi-page forms" a number of times in the past), but if the "additional_emails" functionality was removed completely, without a clear replacement, that would be sad news indeed.
I guess I'll install it on a sandbox site and look into this more!
#26 Some feedback from Webform 3.x
Submitted by akalata (not verified) on Mon, 07/12/2010 - 13:13.
Eric, in case you get around to playing with the 3.x betas, here's my experience:
Using the "module method" originally described in your post, I cannot get webform submissions to send, BUT can successfully generate other emails (such as a test of the SMTP Auth module) to the aliases defined in the module. So we know the module is okay, just doesn't play nice with webform anymore.
Right now I'm poking through what /index.php/cat/c3_Abendtaschenquicksketch provided at http://drupal.org/project/webform_php, and hoping to figure out that module's code enough to modify it with your "module method" code.
#27 3.x Beta
Submitted by Eric Weik on Tue, 07/13/2010 - 11:03.
Thanks for the feedback! I knew that the webform['additional_emails'] method no longer words in the 3.x beta, but I don't know why implementing hook_mail_alter() in a module would not work (since it should be altering core drupal_mail() behaviors independently of Webform.module).
I will look into this further myself.
Post new comment