Magento – Custom email contact form with notification system

mailboxes

In this article, hopefully, you will learn how to create a module that uses its own controller, programatically creates a block based on core template and assigned via file, handles form submission and utilizes Magento notification system to output the notifications to user.

Although the module it self might look relatively simple in the end, keep in mind that these are powerful concepts that you can latter reuse for much more complex requirements.

file 1:
/app/etc/modules/Inchoo_SimpleContact.xml

content of file 1:

<?xml version="1.0"?>
<config>
    <modules>
        <Inchoo_SimpleContact>
            <active>true</active>
            <codePool>local</codePool>
        </Inchoo_SimpleContact>
    </modules>
</config>

file 2: app/code/local/Inchoo/SimpleContact/etc/config.xml

content of file 2:

<?xml version="1.0"?>
<config>
    <modules>
        <Inchoo_SimpleContact>
            <version>0.1.0</version>
        </Inchoo_SimpleContact>
    </modules>
    <frontend>
        <routers>
            <JustSomeFreeRouterNameHereNo1>
                <use>standard</use>
                <args>
                    <module>Inchoo_SimpleContact</module>
                    <frontName>inchoo-simplecontact</frontName>
                </args>
            </JustSomeFreeRouterNameHereNo1>
        </routers>
    </frontend>
</config>

As we dissect our module, the first thing that pops up is the “frontend” element. We can see it has lot of sub-elements of which “routers” is first. In order for something in Magento to be accessible on certain url, that something needs to have controller, like all Zend powered applications. Unlike pure Zend apps, Magento has its own way of mapping controllers, trough xml definitions.

I intentionally used “JustSomeFreeRouterNameHereNo1″ for element name making it self explanatory. You can freely assign name to a router wheres “use” and “args” are two parameters each router should have. Parametar “module” if the full name of your module and “frontName” is the actual url path trough which you acccess your controller. In example above I would access my controller indexAction() method trough url like http://shop.local/index.php/inchoo-simplecontact/index/ or http://shop.local/index.php/inchoo-simplecontact/. In case we have url rewrite set up we can even access it by omitting the “index.php” part from url.

Now we will look into the content of IndexController.php.

file 3: app/code/local/Inchoo/SimpleContact/controllers/IndexController.php

content of file 3:

<?php
class Inchoo_SimpleContact_IndexController extends Mage_Core_Controller_Front_Action
{
    public function indexAction()
    {
        //Get current layout state
        $this->loadLayout();
        $block = $this->getLayout()->createBlock(
            'Mage_Core_Block_Template',
            'inchoo.simple_contact',
            array(
                'template' => 'inchoo/simple_contact.phtml'
            )
        );
        $this->getLayout()->getBlock('content')->append($block);
        //$this->getLayout()->getBlock('right')->insert($block, 'catalog.compare.sidebar', true);
        $this->_initLayoutMessages('core/session');
        $this->renderLayout();
    }
    public function sendemailAction()
    {
        //Fetch submited params
        $params = $this->getRequest()->getParams();
        $mail = new Zend_Mail();
        $mail->setBodyText($params['comment']);
        $mail->setFrom($params['email'], $params['name']);
        $mail->addTo('somebody_else@example.com', 'Some Recipient');
        $mail->setSubject('Test Inchoo_SimpleContact Module for Magento');
        try {
            $mail->send();
        }
        catch(Exception $ex) {
            Mage::getSingleton('core/session')->addError('Unable to send email. Sample of a custom notification error from Inchoo_SimpleContact.');
        }
        //Redirect back to index action of (this) inchoo-simplecontact controller
        $this->_redirect('inchoo-simplecontact/');
    }
}
?>

Above file, although simple, demonstrates two powerful concepts. First we have an example of creating a block “on the fly”. There are several ways one can add an output block to be shown in Magento, this is the “hardest” way. Most of the materials you will find on the web will show you how to do it from xml files. However, I want you to know how to do it from code.

There is one important reason why you should now how to do this from code: Simplicity! If you were to output the block from layout files then you are adding at leas one more file to your module. The more files you have in your module, bigger the chance for bugs. This is really something you should consider and keep in mind for modules who actually require controllers and are not very user centric.

When I say “not very user centric” I think in terms where designer needs to have full control of layout and the way it is arranged. However in cases where not much layout modifications will be required on custom made controller output I believe that “saving yourself” from writing another layout file is the right way to go.

Note that inside the method call createBlock i use ‘Mage_Core_Block_Template’ as one of the parameters. This is the block class. In this example core block template is used. However, you can freely use one of your own declared blocks (will be shown in latter modules). Created block is appended (inserted actualy) in existing block named “content”. Block “content” is one that is almost always present in the output.

Inside the sendemailAction method we have another important concept, the notification system example. Catch exception block triggers the “adding in the notification message” to the session storage. There are few different storage mechanism inside the Magento. Most of them simply extend core/session without any noticeable diference, therefore unles you wish to extend the existing and write your own, you can use the Mage::getSingleton(‘core/session’). You can use 4 diferent types of notification messages: error, warning, notice, success. Which you can call respectively like trough methods addError(’Custom error here’), addWarning(’Custom warning here’), addNotice(’Custom notice here’), addSuccess(’Custom success here’) as shown above.

Any notifications added to ‘core/session’ storage are outputted to frontend trough view files. For instance one such example is app/design/frontend/default/default/template/page/3columns.phtml file. Inside the file there is the < ?php echo $this->getChildHtml(‘global_messages’) ?> line of code that outputs all global notifications. Note that the “global_messages” referes to block name from within the page.xml layout file, which in turn referes to Magento “core/messages” (Mage_Core_Block_Messages) class type.

Final file for our module is the view file itself. As you might notice from the IndexController, we are using the ‘inchoo/simple_contact.phtml’ as one of the parameters passed to createBlock method. What this means is that our module is going to look for app/design/frontend/default/default/template/inchoo/simple_contact.phtml file. Note that if we were to assign diferent template then “default” to be used for our site then ‘inchoo/simple_contact.phtml’ would refer to folder and file from within that template. If that file is not find in this “other” template then the system would look for one in default template.

file 4: app/design/frontend/default/default/template/inchoo/simple_contact.phtml

content of file 4:

<div class="box simple_contact">
<form id="simple_contact_form" name="simple_contact_form" action="<?php echo $this->getUrl('inchoo-simplecontact/') ?>index/sendemail" method="post">
    <fieldset class="group-select">
        <h4 class="legend">Inchoo_SimpleContact module sample</h4>
        <ul>
        <li>
                <div class="input-box">
                    <label for="name">Gimme your name <span class="required">*</span></label><br />
                    <input name="name" id="name" title="Name" value="" class="required-entry input-text" type="text" />
                </div>
                <div class="input-box">
                    <label for="email">And your email <span class="required">*</span></label><br />
                    <input name="email" id="email" title="Email" value="" class="required-entry input-text validate-email" type="text" />
                </div>
                <div class="clear"></div>
                <div class="input-box">
           &nbsp;        <label for="comment">Some comment?</label><br />
                    <textarea name="comment" id="comment" title="Comment" class="required-entry input-text" style="height:100px;" cols="50" rows="3"></textarea>
                </div>
                </li>
                </ul>
    </fieldset>
    <div class="button-set">
        <p class="required">* Required Fields</p>
        <button class="form-button" type="submit"><span>Submit</span></button>
    </div>
</form>
</div>

Content of above file is mostly HTML related so there is not much to talk about it.

That’s it, the end.

39
Top

Care to rate this post?

Author

Branko Ajzele

Ex Inchooer

Worked at Inchoo as a Backend Developer/CTO from 2008 to 2013

Other posts from this author

Discussion 39 Comments

Add Comment
  1. Thanks, I got some ideas after reading this article.

  2. james anelay

    leas ,
    least*

  3. If i wanted the ability to upload a file using the contact page, how would i go about doing this?

  4. John

    Hi! Great tutorial, I’ve created my own form that works great. However, I’m getting a lot of spam through the form and I need a way to eliminate this. I saw a neat security feature called MathGuard (www.codegravity.com/projects/mathguard) but I’m having a bear of a time implementing it. At this point, I’d settle for a simple security question like “What color is grass?” and if they get it right, the form can process… Please help!

  5. phil

    hi, how to avoid spam on this custom contact form?
    i keep receiving spam using this custom contact form.

    can you help me?thanks

  6. Ahmad

    I have not any access to my module with the url
    http://exampl.com/index.php/inchoo-simplecontact/index.

    What is the problem?
    I follow your post but when I click on the submit button on the form it redirects me to the 404 not found page.

  7. I am using this for a custom form on my site and it works like a charm. There is only one problem…after clicking “submit” button, it takes a very long time to submit, send the email, and redirect.

    It is currently taking about 50-55 seconds after clicking submit to send the email and move on to the next page.

    Can anyone help me understand why this is taking so long?

    Here is my sendemailAction() code:

    class Bleacherbum_AddDealer_IndexController extends Mage_Core_Controller_Front_Action
    {
        public function sendemailAction()
        {
            //Fetch submited params
            $params = $this->getRequest()->getParams();
            $mail = new Zend_Mail();
            $bodytext = '
                Dealer Name: ' . $params['dealer_name'] . '
                Address Line 1: ' . $params['address1'] . '
                Address Line 2: ' . $params['address2'] . '
                City: ' . $params['city'] . '
                State: ' . $params['state'] . '
                Zip/Postal Code: ' . $params['zip'] . '
                Contact Email: ' . $params['email'] . '
                Phone #: ' . $params['phone'] . '
                Website URL: ' . $params['url'] . '
                Notes:
                ' . $params['notes'];
            $mail->setBodyText( $bodytext );
            $mail->setFrom( $params['email'], $params['dealer_name'] );
            // $mail->addTo( 'addadealer@streetfxseries.com', 'Add A StreetFX Dealer' );
            $mail->addTo( 'mwilliams@buztronics.com', 'Add A StreetFX Dealer' );
            $mail->setSubject( 'New Request to Add Dealer to Locator on StreetFXSeries.com' );
            try {
                $mail->send();
            }
            catch(Exception $ex) {
                Mage::getSingleton( 'core/session' )->addError( 'Unable to send email. Please make sure all required fields are filled out properly.' );
            }
            //Redirect to success message of (this) add-dealer controller
            $this->_redirect( 'add-dealer-success/' );
        }
    }
    
  8. Helder

    It’s a nice guide to understand a little bit more on how to create your own Magento’s plugins. This gives you not only how to create a custom form but also a way to understand how an app works on Magento’s framework.

    I would, however explain it a little different, in fact, I would do steps backwards as I think they are more understandable that way, but still it has been a great help.

  9. neetesh

    how to call this custom contact form in home page

  10. Rohan

    Hi Neetesh,

    it very simple just goto the cms page find your home page and change the URL enter your form URL it will work…

  11. Rohan

    how to change the layout of this form page by default its 3-column
    I want it as Empty

  12. Christopher

    @Rohan

    Just add the following underneath the frontend in your config.xml file and add the file customform.xml to your layout files.

    customform.xml

  13. @Christopher,

    thanks for your reply

  14. Keiron Roberts

    Is it possible to call a Transactional email when processing the form?

  15. erin

    How about Field validation?

  16. Matt W

    @Erin:

    Check out this link for more thorough instructions:
    http://fishpig.co.uk/blog/magento-forms-prototype-javascript-validation.html

    The most important part is creating the form as a form in the form’s JS. Add this below your form:

    <script type="text/javascript">
    var myForm = new VarienForm( 'form_id' );
    </script>
    

    Insert the ID you assigned to the form in the ‘form_id’ spot. You can name the var anything you want as long as it is not used in other places. There are multiple classes that you can assign to individual form elements that will interact with the JS validation assuming you have your form set up.

  17. Alan

    How can i get some variable of my groupon deal to the form?

  18. Matt W

    @Alan:
    The easiest way to do what you are describing is to use a slightly different method than described here. This article was written some time ago, and Magento has other ways of completing this task now.

    First off, inside config.xml, we are going to define a new email template, then an event that will listen for a specific event. Add the following inside the ‘global’ section of config.xml:

      &lt;events&gt;
        &lt;your_event_name&gt;
          &lt;observers&gt;
            &lt;your_listener_name&gt;
              &lt;type&gt;singleton&lt;/type&gt;     &lt;class&gt;Namespace_Module_Model_Observer&lt;/class&gt;
              &lt;method&gt;sendNotificationEmail&lt;/method&gt;
    &lt;!-- If you had more listeners for this even to set up, you could do that here.  You can also set up new events by adding them inside the events tag --&gt;
            &lt;/your_listener_name&gt;
          &lt;/observers&gt;
        &lt;/your_event_name&gt;
      &lt;/events&gt;
      &lt;template&gt;
        &lt;email&gt;
          &lt;your_template_name translate=&quot;label&quot;&gt;
            &lt;label&gt;Send Notification Email&lt;/label&gt;
            &lt;file&gt;your_email_template.html&lt;/file&gt;
            &lt;type&gt;html&lt;/type&gt;
          &lt;/your_template_name&gt;
        &lt;/email&gt;
      &lt;/template&gt;
    

    * Note: the email template is an HTML file and NOT a PHTML file.

    Next, inside your the action you are calling when the form is submitted, process your info as necessary and then make a call to Mage::dispatchEvent() before you redirect to the next page. This will dispatch the event that we set up in our config, and trigger our listener to fire the method we assigned to it. Example:

    Mage::dispatchEvent( 'your_event_name', array( 'email' =&gt; $email, 'var1' =&gt; $var1, 'var2' =&gt; $var2 ) );
    

    * Note: ‘your_event_name’ will be whatever you defined inside the first tag inside of the events tag in config.xml. The array in the second argument is the array of values you want to pass to the listener function.

    Next, create a file called Observer.php inside your Model folder. Inside Observer.php:

    class Namespace_Module_Model_Observer
    {
    /* The name of this function will be the same as the function name you put inside the &lt;method&gt; tag in config.xml */
    public function sendNotificationEmail($params)
    {
    // $params is the array of options that will be passed to the function when the event is dispatched.
    $email = $params['email'];
    $var1 = $params['var1'];
    $var2 = $params['var2'];
    $fromEmail = 'you@yourcompany.com';
    $fromName = &quot;Sender's Name&quot;;
    $toEmail = 'recipient@theircompany.com';
    $toName = &quot;Recipient's Name&quot;;
    $subject = 'Message Subject Here!';
    // This loads the Magento email template object and your custom email template.
    $emailTemplate  = Mage::getModel( 'core/email_template' )
    -&gt;loadDefault( 'your_template_name' ); // this was defined in config.xml
    //Create an array of variables to assign to template
    $vars = array();
    $vars['email'] = $email;
    $vars['var1'] = $var1;
    $vars['var2'] = $var2;
    $translate  = Mage::getSingleton( 'core/translate' );
    $translate-&gt;setTranslateInline( true );
    $emailTemplate-&gt;setSenderName( $fromName ); // Set sender name
    $emailTemplate-&gt;setSenderEmail( $fromEmail ); // Set sender email
    $emailTemplate-&gt;setTemplateSubject( $subject ); // Set email subject
    $processedTemplate = $emailTemplate-&gt;getProcessedTemplate( $vars ); // This array tells the template to lookout for the variables you will use in the email template.
    $emailTemplate-&gt;send( $toEmail, $toName, $vars ); // Send the email with the variables' values stored in the $vars array
    }
    

    Finally, create your email template file. You will be creating it inside magentoRoot/app/locale/en_US/template/email/. Your template will be just regular HTML, but you can call the variables that you passed like so:

    Email: {{var email}}&lt;br /&gt;
    Var1: {{var var1}}&lt;br /&gt;
    Var2: {{var var2}}&lt;br /&gt;
    

    I hope this helps. Let me know if you have any questions!

  19. sathiyamoorthy

    how to add additional fields along with this

  20. Samuel

    Hi,

    How to add captcha to this form. Please help me

  21. lalita

    i want to create prescription form for every product and save it in backend with the ordered product . how can i achieve this in magento please answer ASAP.

  22. Christian

    Hi the form seems to be working fine which is great however how do i define the template of the “success page” to 1column?

  23. Kstor

    Hello, great tuto thx !!
    By the way i have a problem when posting my form, i get a 404. Event hough i get the url in the action parameter (http://myDomain.com/inchoo-simplecontact/index/sendemail/).
    I really don’t see what’s going wrong.
    If anybody have some feedback :)
    Thx in advance.

  24. Hello, i loved your tutorial i was able to create a custom form and access it on the local server using the url format that you showed.
    http://localhost/website/index.php/contest

    but when i uploaded the module on to the server i cannot access it using the URL format

    http://www.website.org/index.php/contest

    it gives me 404 not found error . what am i doing wrong

  25. Marek

    …always redirected to 404, not able send message, could be routers config.xml ?

  26. Marek

    works 100%, my fault

  27. i m getting following error on submitting the data.how can i solve it?
    “Unable to send email. Sample of a custom notification error from Inchoo_SimpleContact.”

  28. khushbu
  29. tushar

    still i can’t receive contact us mail in my magento 1.7 site if anybody knows solution for this issue please help me!

  30. munendra Kumar

    Hi,
    I want to change the sender address from “website8@box867.bluehost.com” to “customercare@somewebsite.com”.

  31. Hi,

    Is there any way to implement a simple WYSIWYG editor into the contact form to allow for formatting such as line breaks, etc? All of the emails that come through from this form offer no formatting whatsoever and it would be great to figure out how to implement a very light WYSIWYG editor like Redactor (http://imperavi.com/redactor/).

  32. i am always getting 404 error what am doing wrong please help me ASAP…..

  33. stefan

    Hey,

    How could I add this custom form to a cms page and get it working.

    I’ve added {{block type=”core/template” template=”inchoo/simple_contact.phtml”}} to my cms page but the form action /index/sendemail returns to a 404 page, hence the email is not sent?

    Thanks

    Stefan

  34. Maha

    Hello,

    Thanks for sharing all this amazing knowledge!

    I have got the form to work and send emails. However, I am unable to get the success message to work by using:

    Mage::getSingleton(‘core/session’)->addSuccess(‘success message’);

    I have tried adding this piece of code before the redirect and after it. In both cases, the submit button just gives me a blank page!

    what could possibly be wrong with that :/ ?

  35. Michal

    Thank you for the Script. I’ve the problem that I don’t got the success message. I received the mail, but got no message on the frontend?! Any idea? Thanks.

  36. Nandakumar

    HI,

    How to call custom form in the template…. some 404 error is coming.

    Need your support.

    Thanks

  37. Gerard

    Great tutorial!

    But what if I want this contact form not on http://shop.local/index.php/inchoo-simplecontact/ but in my right sidebar on all the pages that do have that sidebar.

  38. Juan

    Thank you, very useful.

  39. Mon

    Thanks very much! Works beautifully!!

Add Your Comment

Please wrap all source codes with [code][/code] tags.
Top