Sending Custom Emails using Custom Module in Magento 2 (Updated)
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;
use Magento\Store\Model\StoreManagerInterface;
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;
protected $storeManager;
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,
StoreManagerInterface $storeManager
array $data = []
)
{
$this->_inlineTranslation = $inlineTranslation;
$this->_transportBuilder = $transportBuilder;
$this->_scopeConfig = $scopeConfig;
$this->_logLoggerInterface = $loggerInterface;
$this->messageManager = $context->getMessageManager();
$this->storeManager = $storeManager;
parent::__construct($context);
}
public function execute()
{
$post = $this->getRequest()->getPost();
try
{
// Send Mail
$this->_inlineTranslation->suspend();
$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' => $this->storeManager->getStore()->getId()
]
)
->setTemplateVars([
'name' => $post['name'],
'email' => $post['email']
])
->setFromByScope($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"}}
Want to test this mail in your localhost? follow this link.
If this post helps you, then please like us on Facebook and follow us on Twitter.

