Magento – Custom email contact form with notification system

Magento – Custom email contact form with notification system

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.

You made it all the way down here so you must have enjoyed this post! You may also like:

Add Pagination to Custom Collection in Magento Dario Trbovic
Dario Trbovic, | 7

Add Pagination to Custom Collection in Magento

Enabling Multi-part MIME Emails in Magento Tomislav Nikcevski
Tomislav Nikcevski, | 3

Enabling Multi-part MIME Emails in Magento

Programmatically add a custom block in Magento Admin Kristijan Glibo
Kristijan Glibo, | 4

Programmatically add a custom block in Magento Admin

60 comments

  1. Custom form works perfectly on other versions of magento. But when I upgraded, it stopped working.

  2. {{block type=”core/template” template=”inchoo/simple_contact.phtml”}}

    this block code not working in CMS page on magento 1.9.2.4. any one help me

  3. There seems to be a difference in the form action:

    This does not work:
    getUrl('inchoo-simplecontact/') ?>index/sendemail

    This does work:
    getUrl('inchoo-simplecontact/index/sendemail') ?>

  4. 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/’ );
    }
    }

  5. if we submit the form who can able to receive the mail? it take it from store general contact or contact us email?

  6. HI, this is really nice article.

    I did not understand what is the use of . Can you please explain it.

    I also want to know why form validation is not working.

  7. Iam new to magento and i want to add custom code in magento.
    I place the same content with tags whatever you given.Just i want to know, how to access that page in browser? my website is : magento.2muchstore.com

    Anybody tell that thing is very greatful for me.Thanks in advance.

  8. what does the line
    getUrl(‘inchoo-simplecontact/’) ?>index/sendemail”

    mean cos i am trying to creating a Question form so i have changed a few names and references however when i change this line it does not send the email or do anything.

  9. HI,

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

    Need your support.

    Thanks

  10. 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.

  11. 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 :/ ?

  12. 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

  13. 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/).

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

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

  16. 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.”

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

  18. 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.

  19. @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:

      <events>
        <your_event_name>
          <observers>
            <your_listener_name>
              <type>singleton</type>     <class>Namespace_Module_Model_Observer</class>
              <method>sendNotificationEmail</method>
    <!-- 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 -->
            </your_listener_name>
          </observers>
        </your_event_name>
      </events>
    
      <template>
        <email>
          <your_template_name translate="label">
            <label>Send Notification Email</label>
            <file>your_email_template.html</file>
            <type>html</type>
          </your_template_name>
        </email>
      </template>

    * 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' => $email, 'var1' => $var1, 'var2' => $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 <method> 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 = "Sender's Name";
    
    $toEmail = 'recipient@theircompany.com';
    $toName = "Recipient's Name";
    $subject = 'Message Subject Here!';
    
    // This loads the Magento email template object and your custom email template.
    $emailTemplate  = Mage::getModel( 'core/email_template' )
    ->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->setTranslateInline( true );
    
    $emailTemplate->setSenderName( $fromName ); // Set sender name
    $emailTemplate->setSenderEmail( $fromEmail ); // Set sender email
    $emailTemplate->setTemplateSubject( $subject ); // Set email subject
    
    $processedTemplate = $emailTemplate->getProcessedTemplate( $vars ); // This array tells the template to lookout for the variables you will use in the email template.
    
    $emailTemplate->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}}<br />
    Var1: {{var var1}}<br />
    Var2: {{var var2}}<br />

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

  20. @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.

  21. @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

    1. Sorry i didn’t get your code visible on screen. Stuck in the same problem kindly guide me through. I also want the template to be empty.

  22. 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…

  23. 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.

  24. 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/' );
        }
    }
  25. hi, how to avoid spam on this custom contact form?
    i keep receiving spam using this custom contact form.

    can you help me?thanks

  26. 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!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <blockquote cite=""> <code> <del datetime=""> <em> <s> <strike> <strong>. You may use following syntax for source code: <pre><code>$current = "Inchoo";</code></pre>.

Tell us about your project

Drop us a line. We'd love to know more about your project.