branko ajzele, senior developer / project manager

Posts / Articles

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/ActiveCodeline_SimpleContact.xml

content of file 1:

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

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

content of file 2:

<?xml version="1.0"?>
 
<config>
    <modules>
        <ActiveCodeline_SimpleContact>
            <version>0.1.0</version>
        </ActiveCodeline_SimpleContact>
    </modules>   
 
    <frontend>
        <routers>
            <JustSomeFreeRouterNameHereNo1>
                <use>standard</use>
                <args>
                    <module>ActiveCodeline_SimpleContact</module>
                    <frontName>activecodeline-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/activecodeline-simplecontact/index/ or http://shop.local/index.php/activecodeline-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/ActiveCodeline/SimpleContact/controllers/IndexController.php

content of file 3:

<?php
 
class ActiveCodeline_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',
            'activecodeline.simple_contact',
            array(
                'template' => 'activecodeline/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 ActiveCodeline_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 ActiveCodeline_SimpleContact.');
 
        }
 
        //Redirect back to index action of (this) activecodeline-simplecontact controller
        $this->_redirect('activecodeline-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 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 ‘activecodeline/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/activecodeline/simple_contact.phtml file. Note that if we were to assign diferent template then “default” to be used for our site then ‘activecodeline/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/activecodeline/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('activecodeline-simplecontact/') ?>index/sendemail" method="post">
 
    <fieldset class="group-select">
        <h4 class="legend">ActiveCodeline_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.

View Comments

  1. Bryan Houghton II /

    Thank you very much for a very informative tutorial. This is really helpful especially for magento beginners like me.

    I’m following it right now. By the way do you have an idea on how you can send an email to a customer using a custom template? Similar to a product alert.

    Thanks again. Really good articles. :)

  2. Bryan Houghton II /

    Hi Guys,

    I’ve managed to found a solution for getting an email template.

    Here is my solution, Hope it helps.

    Email Template – brands.phtml

    customer_name; ?>
    Welcome!!!

    New products for brandname; ?>

    <img src=”product_image; ?>” />

    Thank you very much for subscribing

    PHP Code

    setScriptPath(ROOT_DIR);

    Mage::log($html->getScriptPaths());

    // assign values
    $html->assign(‘customer_name’, ‘John Doe’);
    $html->assign(‘brandname’, ‘MyBrandname’);
    $html->assign(‘product_image’, ‘Your Image’);

    // render view
    $bodyText = $html->render(‘brands.phtml’);

    ?>

  3. Hi all, a bit off topic: can anybody help me use the url rewrite management to redirect a main category to a sub-category?!… I’ve searched, searched, searched and found no solution! :(

  4. slimshock /

    I can’t make this stuff working.. i follow everything butstill no luck.. anybody try this stuff working?..

  5. Bryan Houghton II /

    Hi Slimshock,

    I’ve managed to get it working. Are there any error messages being displayed.

    One of the problem I came across with is that the email isn’t sending. Is this is the problem you are encountering?

  6. Nexus Rex /

    I too cannot get this to work. I get the “404 Not Found” page:
    http://www.clearprotector.com/activecodeline-simplecontact/

    Thanks for any help.

    -Travis Cable

  7. Nexus Rex /

    Got it working—stupid mistake on my part. Now any idea how to get form validation added into this?

  8. Thanks for this walk through. Worked great.

    Steve

  9. For those of you wanting to use a email template, this code is from the Mage_Contact module and demonstrates how (in the IndexController.php):

    $mailTemplate = Mage::getModel('core/email_template');
                    /* @var $mailTemplate Mage_Core_Model_Email_Template */
                    $mailTemplate-&gt;setDesignConfig(array('area' =&gt; 'frontend'))
                        -&gt;setReplyTo($post['email'])
                        -&gt;sendTransactional(
                            Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE),
                            Mage::getStoreConfig(self::XML_PATH_EMAIL_SENDER),
                            Mage::getStoreConfig(self::XML_PATH_EMAIL_RECIPIENT),
                            null,
                            array('data' =&gt; $postObject)
                        );
     
                    if (!$mailTemplate-&gt;getSentSuccess()) {
                        throw new Exception();
                    }
  10. Thanks this is really good article.
    It has help me lot.

    Would you please tell how to do validation in magento way (as done on contact form)?

  11. i follow all the instillation but not working

  12. ChefMaha /

    thanks alot for this useful tuturial.

    I'd like to know how to change the page layout from 3-columns to 2-columns right.

    thank you

  13. Himali /

    This is perfect. working great

  14. ChefMaha /

    Hi

    does anybody know how to

    1.include a validation for required fields
    2. preserve the values of the fields when the page refreshes

    thank you

  15. Where and how I do that?

    TIA

  16. How can i set the page template to 1 column ?

  17. Just add

    <script type=”text/javascript”>
    //<![CDATA[
    var contactForm = new VarienForm('contactForm', true);
    //]]>

    to the bottom of your simple_contact.phtml file
    </script>

    to your

  18. when the fields are empty and you press send i get an error message. this works great. but how do i get a succes message when the fom is send? any ideas how i can fix this?

  19. nevermind. fixed it :)

    code:

    try {
    $mail->send();

    Mage::getSingleton('core/session')->addSuccess('Your succes message.');
    $this->_redirect('*/*/');
    }

  20. What file is this code placed in?

  21. i found it use this code to replace line 43 in your indexController.php file

  22. What file is this code placed in?

  23. i found it use this code to replace line 43 in your indexController.php file

  24. ChefMaha /

    Hey Paul,

    for some reason, with me it's the opposite. I get a success msg but no error message for submitting empty form.

    any idea?

  25. ChefMaha /

    Hey Ben,

    thanks for the solution. But adding those lines of code does not change a thing: No validation. No value preserve.

    thanks again

  26. Hello,
    I got the same error 404, please tell us, what was the mistake you did.

    San.

  27. hello dear
    i want to send body of mail would be like
    name:
    email:
    comments:

    but i am using this $mail->setBodyText($params['comment']);

    so it is sending only comments in mail, so can u tell me how m i gonna do what i wrote above. thanks
    plz mail me vaseem@doomshell.com
    Thanks
    http://www.vaseemansari.blogspot.com

  28. yes.. how did you counter this? No error messages or email coming through

  29. Soraerae /

    I am having the same problem, that I need more than just the comments to be sent to me. Did you figure out a solution to this?

  30. hello dear Soraerae
    this is vaseem ansari and i have figured out how to send more text or more description in comments
    suppose u want to send email id, phone no and comments and other fields also, then i can help u,
    if u have resolved the issue then its okey and if u have not u can mail me at vaseem@doomshell.com
    i can provide u the solution for this problem.

  31. Soraerae /

    Hello I sent you an email, did you get it? I am still looking for a solution

  32. atoz /

    Hello all,
    I have made a payment extension and that will create a pdf after the successful checkout. for that i want to put a link in the success page so the user can download the pdf from there. how coukld i make this happen from my module itself please help ……..

  33. Hello there. I am dying to know how to send more text or more description from other fields within the comments parameter – please help! Thanks so much!!

  34. Please tell me how to recieve additional information from other fields within the 'comments' parameter in the setBodyText — Thanks so much!

  35. @amy

    To receive additional information you want to format it as such:
    $mail->setBodyText(“Name: ” . $params['name'] . “, Comment: ” . $params['comment']. “, Email:” . $params['email']);

    This will display the three fields in your email content, if you want to add another field to the form you can do so in simple_contact.phtml just make sure you give it a unique name, id and title then add $params[<your new field name>] to the setBodyText function.

  36. Brady /

    This works great! Thanks so much for the tutorial.

    One question – how do I set the Page Title? In 1.3.2.4 it seems to take the default page title set in the Admin. In 1.4.1.1 the Page Title reports ’404 Not Found’

  37. Brady /

    Thanks Jonathan,

    I know it’s been 10 months, but would you be able to elaborate on how you were able to implement this? Looks promising!

blog comments powered by Disqus