Sending Custom Emails using Custom Module in Magento 2

Sending Custom Emails using Custom Module in Magento 2

Emails are an essential part of any e-commerce website. Magento 2 by default provides many emails templates. You can check all the available email templates from Magento 2 admin panel under Marketing > Communications > Email Templates. Click “Add New Template”. Under “Load default template” you can see the Template list.

We can override any of this default template as per our need. But what if we want to create our own unique template to sending custom emails from a custom module. Well, In this article we are going to create new sample module and in that module, we will create a form, on submit of that form we will send form information by sending a custom email. This email will use custom email template.

Module Setup

Before we start creating files for the modules. Let’s look at the module structure and important files at a glance. We will create a module named “Customemail”.
 

app/code/Codextblog/Customemail/etc/module.xml – This file is a module configuration file.

app/code/Codextblog/Customemail/registration.php – This file is module registration file that register our module in magento 2 system.

app/code/Codextblog/Customemail/etc/frontend/routes.xml – This file is responsible for frontend routing of our module

app/code/Codextblog/Customemail/Controller – This directory contains controller files

app/code/Codextblog/Customemail/Block – This directory contain block php file which is responsible for view logic.

app/code/Codextblog/Customemail/view/frontend/layout – This directory contain layout xml file.

app/code/Codextblog/Customemail/view/frontend/templates – This directory contain template file which render HTML.

app/code/Codextblog/Customemail/view/frontend/email – This directory contain email template which is use for sending custom email in our module

Getting Started: Development

Step 1: Create module.xml file under app/code/Codextblog/Customemail/etc directory

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd">
    <module name="Codextblog_Customemail" setup_version="1.0.0"></module>
        <sequence>
            <module name="Magento_Backend"/>
             <module name="Magento_Sales"/>
            <module name="Magento_Quote"/>
            <module name="Magento_Checkout"/>>
        </sequence>
</config>

Step 2: Create registration.php file under app/code/Codextblog/Customemail/

<?php

\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Codextblog_Customemail',
    __DIR__
);

Step 3: Create frontend router file routes.xml under app/code/Codextblog/Customemail/etc/frontend

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/App/etc/routes.xsd">
    <router id="standard">
        <route id="customemail" frontName="customemail">
            <module name="Codextblog_Customemail" />
        </route>
    </router>
</config>

we have defined the frontend name of our module to “customemail”. Whenever we visit www.example.com/customemail/controllername It will look for controller file from our module.

Now Let’s create a controller file.

Step 4: Create Index.php file under app/code/Codextblog/Customemail/Controller/Index directory

<?php

namespace Codextblog\Customemail\Controller\Index;

class Index extends \Magento\Framework\App\Action\Action
{
    public function execute()
    {

        $this->_view->loadLayout();
        $this->_view->getLayout()->initMessages();
        $this->_view->renderLayout();
    }
}

Here we have created Index controller hence, our frontend URL will be like www.example.com/customemail/index/

Now let’s create block and frontend view files.

Step 5: Create Index.php block file under app/code/Codextblog/Customemail/Block/Index directory

<?php

namespace Codextblog\Customemail\Block\Index;


class Index extends \Magento\Framework\View\Element\Template {

    public function __construct(\Magento\Catalog\Block\Product\Context $context, array $data = []) {

        parent::__construct($context, $data);

    }


    protected function _prepareLayout()
    {
        return parent::_prepareLayout();
    }

}

Step 6: Create customemail_index_index.xml layout fiel under app/code/Codextblog/Customemail/view/frontend/layout directory

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">

	<head>
        <title>Custom Contact Form</title>
    </head> 

    <body>

		<referenceContainer name="content">
            <block class="Codextblog\Customemail\Block\Index\Index" name="customemail_index_index" template="Codextblog_Customemail::customemail_index_index.phtml"/>
        </referenceContainer>

	</body>
</page>

Step 7: Create template file customemail_index_index.phtml under app/code/Codextblog/Customemail/view/templates directory. In this file we are define html form that post data to our controller.

<form action="<?php echo $block->getBaseUrl().'customemail/index/post/';?>" name="customemaildata" method="post" id="contactForm-1" data-hasrequired="<?php echo __('* Required Fields') ?>" data-mage-init='{"validation":{}}'>
	<fieldset class="fieldset">
			<div class="field email required">
                <label class="label" for="email"><span><?php  echo __('Name') ?></span></label>
                <div class="control">
                    <input name="name" id="name" title="<?php echo __('Name') ?>" class="input-text" type="text" data-validate="{required:true}"/>
                </div>
            </div>
        	<div class="field email required">
                <label class="label" for="email"><span><?php  echo __('Email') ?></span></label>
                <div class="control">
                    <input name="email" id="email" title="<?php echo __('Email') ?>" class="input-text" type="email" data-validate="{required:true, 'validate-email':true}"/>
                </div>
            </div>                        
	</fieldset>
	<div class="actions-toolbar">
        <div class="primary">
            <input type="hidden" name="hideit" id="hideit" value="" />
            <button type="submit" title="<?php echo __('Submit') ?>" class="action submit primary">
                <span><?php echo __('Submit') ?></span>
            </button>
        </div>
    </div>
</form>

Step 8: Our form is submitting data to post action so let’s create Post.php under app/code/Codextblog/Customemail/Controller directory

<?php
namespace Codextblog\Customemail\Controller\Index;

use Zend\Log\Filter\Timestamp;

class Post extends \Magento\Framework\App\Action\Action
{
    const XML_PATH_EMAIL_RECIPIENT_NAME = 'trans_email/ident_support/name';
    const XML_PATH_EMAIL_RECIPIENT_EMAIL = 'trans_email/ident_support/email';
    
    protected $_inlineTranslation;
    protected $_transportBuilder;
    protected $_scopeConfig;
    protected $_logLoggerInterface;
    
    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Framework\Translate\Inline\StateInterface $inlineTranslation,
        \Magento\Framework\Mail\Template\TransportBuilder $transportBuilder,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Psr\Log\LoggerInterface $loggerInterface,
        array $data = []
        
        )
    {
        $this->_inlineTranslation = $inlineTranslation;
        $this->_transportBuilder = $transportBuilder;
        $this->_scopeConfig = $scopeConfig;
        $this->_logLoggerInterface = $loggerInterface;
        $this->messageManager = $context->getMessageManager();
        
        
        parent::__construct($context);
        
        
    }
    
    public function execute()
    {
        $post = $this->getRequest()->getPost();
        try
        {
            // Send Mail
            $this->_inlineTranslation->suspend();
            $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE;
            
            $sender = [
                'name' => $post['name'],
                'email' => $post['email']
            ];
            
            $sentToEmail = $this->_scopeConfig ->getValue('trans_email/ident_general/email',\Magento\Store\Model\ScopeInterface::SCOPE_STORE);
            
            $sentToName = $this->_scopeConfig ->getValue('trans_email/ident_general/name',\Magento\Store\Model\ScopeInterface::SCOPE_STORE);
            
            
            $transport = $this->_transportBuilder
            ->setTemplateIdentifier('customemail_email_template')
            ->setTemplateOptions(
                [
                    'area' => 'frontend',
                    'store' => \Magento\Store\Model\Store::DEFAULT_STORE_ID,
                ]
                )
                ->setTemplateVars([
                    'name'  => $post['name'],
                    'email'  => $post['email']
                ])
                ->setFrom($sender)
                ->addTo($sentToEmail,$sentToName)
                //->addTo('owner@example.com','owner')
                ->getTransport();
                
                $transport->sendMessage();
                
                $this->_inlineTranslation->resume();
                $this->messageManager->addSuccess('Email sent successfully');
                $this->_redirect('customemail/index/index');
                
        } catch(\Exception $e){
            $this->messageManager->addError($e->getMessage());
            $this->_logLoggerInterface->debug($e->getMessage());
            exit;
        }
        
        
        
    }
}

Under execute method we have written email send code using a “transportBuilder” object which we have injected in our constructor method. Using this object we are calling several methods to set require email parameters. The first method “setTemplateIdentifier” set email template identifier to “customemail_email_template” which is our custom email template identifier which we will define in next step. Second method “setTemplateOptions” set options ‘frontend’ and current store code. If we would send email from backend module then we set ‘admin’. Third method “setTemplateVars” set the variables which we can call in our email template. Further, we have called “setFrom” and “addTo” methods which are sets receipt and sender emails.

Step 9: Declare email template in email_templates.xml file Under app/code/Codextblog/Customemail/etc directory

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Email:etc/email_templates.xsd">

	<template id="customemail_email_template" label="Email Form" file="customemail.html" type="html" module="Codextblog_Customemail" area="frontend"/>
	
</config>

Here we have declared our email template “customemail.html” with id “customemail_email_template”. This id need to pass in “setTemplateIdentifier” function. In Step 7, we have done the same. Now let’s create actual email template HTML file.

Step 10: Create customemail.html under app/code/Codextblog/Customemail/view/frontend/email directory

<!--@subject Sending email from my custom module @-->

{{template config_path="design/email/header_template"}}
<table>
	 <tr class="email-intro">
		 <td>
		 Email: {{var email}}
		 </td>
		 <td>
		 Name: {{var name}}
		 </td>
	 </tr>
 </table>

{{template config_path="design/email/footer_template"}}

 

Not getting success? Purchase ready to use module

What you will get in purchase?
  • Working source code of this tutorial
  • Email support


 
If you liked this post, then please like us on Facebook and follow us on Twitter.

Leave a Comment

(22 Comments)

  • chandan kumar

    Form is not showing i have followed all the step from begining but not showing form

  • Andy Allen

    Why are you suspending inlineTranslation?

    this->_inlineTranslation->suspend();

  • Manisha

    Very nice tutorial for custom email template..It’s working perfectly.

  • ashish

    hello i am getting this error Email template ‘customemail_email_template’ is not defined. when i am sending values to admin

  • Alex

    I’ve managed to get it working!!!
    The thing was that Post.php file should be under “app/code/Codextblog/Customemail/Controller/Index” directory, not in the “app/code/Codextblog/Customemail/Controller”.
    Thanks a lot for your helpful tutorial again!

    • Chirag

      Glad to hear you finally got it working. You should very careful while creating module. One small typo or wrong directory can also lead to big error that is very hard to find

      I personally suggest all the developer to create module from beginning when you encounter big unknown errors. That will make you realize any missing file or typo mistake.

  • Alex

    Finally got it working after creating all files from the very beginning, form is showing up at url my.domain.com/customemail/index, but after submitting redirects to 404-page, maybe you have any guess what could it be?

  • Alex

    First of all, thank you for the very detailed tutorial!
    But after accomplishing all the step, compiling setup and having rechecked everything twice, I still having an error when trying to load the page: my.domain.com/customemail/index/

    Here is the error message:
    Exception #0 (Magento\Framework\Config\Dom\ValidationException): Element ‘block’, attribute ‘class’: [facet ‘pattern’] The value ‘NRG\customemail\Block\Index\Index’ is not accepted by the pattern ‘[A-Z][_a-zA-Z\d]*(\\[A-Z][_a-zA-Z\d]*)*’.
    Line: 804

    Element ‘block’, attribute ‘class’: ‘NRG\customemail\Block\Index\Index’ is not a valid value of the atomic type ‘blockClassType’.
    Line: 804

    Would be grateful if you can give some idea why the error occurs…

  • larp

    Error filtering template: Invalid template file: ‘Codextblog_Customemail::customemail_index_index.phtml’ in module: ‘Codextblog_Customemail’ block’s name: ‘index\index_0’.. I am new to magento please help me.

    • Chirag Dodia

      I have just modified the path of email template’s file. Please correct the file path in your code and check again.

  • larp

    No display form..
    I paste this in Page I want to display it.

    but no form is display.

    • Chirag Dodia

      Is there any specific error are you facing on form page? Please check each and every files path and make sure it is correct.

  • larp

    Hello i followed completely your tutorial, now, how to display the custom contact us?

    I paste this on page where I want to display it but nothing happens.

    No Form is displaying.

  • Minaxi

    Hello
    I m using this above code but it shows me error like this
    Uncaught TypeError: Argument 2 passed to VimirLab\HelpDesk\Controller\Index\Save::__construct() must implement interface Magento\Framework\Translate\Inline\StateInterface, none given, called

    • Chirag Dodia

      Please make sure you have added the dependency of \Magento\Framework\Translate\Inline\StateInterface in your construct method same like shows in this post. If you have already included the dependency you just need to run below three command
      php bin/magento setup:upgrade
      php bin/magento setup:di:compile
      php bin/magento setup:static-content:deploy

      After running these command please clear your cache and check.

  • Ajith Kumar

    Thank you for your guidance. It perfectly works for me in magento 2 running in localhost. Keep Doing Your Work..Good Luck Dude.

  • Juliano

    Hello.
    I have followed your post thanks by the way. But Like LadyKea I received the email but not errror however no content either not even harded coded content in customemail.html

    • larp

      Hello use getPostValue() instead of getPost() in Post.php. Hope it helps!

  • TC Buddy

    Hi, I followed your post but I end up with a 404 error, new to magento, plz assist or could you provide a download link to this code that you have tested?

    • LadyKea

      Please help, followed along but form does nothing, no message, no errors just nothing.

      • larp

        Try to upload it on live server. The codes are working. I just modified some codes.

        • pragnesh

          what change you done i have same error plz help me!!!

  • Leave a Reply to Manisha Cancel reply

    All the comments are goes into moderation before approval. Please do not spam. Your email address will not be published. Required fields are marked *

    Enjoy this post? Please support Us!

    Like our social page for daily new updates….


    Want to become
    a Magento 2 Expert?

    If Yes! Then Subscribe to our newsletter and get weekly article to you email id.
    Subscribe Here
    SUBSCRIBE NOW
    close-link

    To Avoid Spam Downloads, We Want Your Email

    We will send you download link right
    away. Please submit form below.
    SEND ME DOWNLOAD LINK
    Close