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.
Leave a Comment
(62 Comments)
When I’m running this Module I got a blank page of custom email so how can I get form
How can we append styles to custom email template, i tried added custom classes but all classes disappear when they passed to email and when we receive that email.
You should follow this link https://nwdthemes.com/2018/05/25/how-to-style-email-templates-in-magento-2/
how can i add attachment to email?
I’m having the main.DEBUG error: Unable to send mail: Unknown error [] [], and in post.php it points out that in the StoreManagerInterface $ storeManager constructor
array $ data = [] is wrong. Has anyone had this problem?
Is it necessary to activate php mail ()?
Yes
How can I send attachments in this form?
Can you Please help me to fix the issue of [2021-01-12 14:36:25] main.CRITICAL: Invalid template file: ‘Codextblog_Customemail::customemail_index_index.phtml’ in module: ‘Codextblog_Customemail’ block’s name: ‘customemail_index_index’ [] [].
Also i am not able to showing the Form.
Can you let me know what is the issue i need to fix this on the urgent bases.
Please help me!!
Make sure the template path mentioned in the layout file is correct.
Hello I followed this tutorial. I am able to access the form and submit it. I am also getting the email sent successfully message but didn’t receive any email. Did you use the general email from stores->settings->store addresses->general contact to receive the email ? Any help will be appreciated. Thanks in advance.
Yes your are right. It’s sending email to general contact.
How to implement this module? I mean, how to make it work or what triggers this module?
After creating all the mentioned files you need to install the module on your Magento 2 site. After successful installation, you can trigger this module on URL http://www.example.com/customemail/
To install the module please follow https://www.codextblog.com/magento-2/how-to-install-a-magento-2-extension-step-by-step-for-beginners/
A blank page is appearing
There must be some error.
Thankyou for this tutorial, I have managed to get the form on screen but when I submit I get a blank screen on customemail/index/post/ page? I’m testing on my localhost
Have you checked Magento log files? May be there is a exception or php error due to that you are getting blank page. If not found in magento log then check apache log.
This is now working (ish), I can send the form, I get the email sent successfully message but it’s sending to owner@example.com and not the store email address that all emails should send to?
This can be changed. Check the sendToEmail variable where I have set the store email address. You can change that line as per your need.
Thankyou, I have done that and it nows sends to my mailbox. Thankyou for your help
When I try to add new fields the form does not send, do you have an email I can send you with what I’ve done to see if I’m doing something wrong?
Is SMTP configuration needed for this?
No. But if your Magento not sending any system mail then you should try SMTP
Don’t know why but customemail/index/post/ this controller shows 302 status code in Network Magento 2 ?
I have created your module and it shows the form when on sending the i didn’t receive any mail in my mailbox.
I have used send-grid for sending the male.
Have you any idea how to get it working ?
Don’t know why bit customemail/index/post/ that controller shows 302 status code in Network will you please help ?
Please check the controller name and its router in routes.xml
No. I have tested this code with default magento and its working. Not tested with sendgrid.
Hi email field value not send add multiple field send email all field value but email field value balnk in mail
Can you please clarify what you want to achieve? Your comment is not able to be understood.
add multiple field in form after submit send all field value in mail but email field value empty send
You have to debug Post.php controller to check whether you are getting email field value in post or not.
Thanks for sharing. Nice tutorial
But I think that folder templates must be inside view >> frontend folder instead of view folder.
Thanks for sharing. Nice tutorial
But I think that file in step 8 i.e. Post.php must be inside app/code/Codextblog/Customemail/Controller/Index directory. Also folder templates must be inside view > frontend instead of view folder.
Thanks brother..It helped me a lot.. I have used this one in product detailed page for ‘report wrong product’ module..Thanks again
I am not getting success messages or error messages on this form.
Please check log file.
When i have create this module and enable the modulle and open the link mystore.com/customemailindex/ the page is show blank no content and error is show please help me to solve this issue and the email template is show in the admin
Please check the error log of that page and tell little bit about the error to find the issue.
Form is not showing i have followed all the step from begining but not showing form
Why are you suspending inlineTranslation?
this->_inlineTranslation->suspend();
Very nice tutorial for custom email template..It’s working perfectly.
hello i am getting this error Email template ‘customemail_email_template’ is not defined. when i am sending values to admin
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!
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.
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?
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…
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.
I have just modified the path of email template’s file. Please correct the file path in your code and check again.
No display form..
I paste this in Page I want to display it.
but no form is display.
Is there any specific error are you facing on form page? Please check each and every files path and make sure it is correct.
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.
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
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.
Thank you for your guidance. It perfectly works for me in magento 2 running in localhost. Keep Doing Your Work..Good Luck Dude.
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
Hello use getPostValue() instead of getPost() in Post.php. Hope it helps!
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?
Please help, followed along but form does nothing, no message, no errors just nothing.
Try to upload it on live server. The codes are working. I just modified some codes.
what change you done i have same error plz help me!!!
Useful Magento 2 Articles
Author Info
Chirag
Connect With MeWas this post helpful? Please support Us!
To Avoid Spam Downloads, We Want Your Email
away. Please submit form below.
Magento 2
Knowledge
to your Inbox