SPECIAL OFFER: ENJOY 3 MONTHS OF SHOPIFY FOR $1/MONTH SPECIAL OFFER: ENJOY 3 MONTHS OF SHOPIFY FOR $1/MONTH SPECIAL OFFER: ENJOY 3 MONTHS OF SHOPIFY FOR $1/MONTH SPECIAL OFFER: ENJOY 3 MONTHS OF SHOPIFY FOR $1/MONTH SPECIAL OFFER: ENJOY 3 MONTHS OF SHOPIFY FOR $1/MONTH SPECIAL OFFER: ENJOY 3 MONTHS OF SHOPIFY FOR $1/MONTH SPECIAL OFFER: ENJOY 3 MONTHS OF SHOPIFY FOR $1/MONTH SPECIAL OFFER: ENJOY 3 MONTHS OF SHOPIFY FOR $1/MONTH SPECIAL OFFER: ENJOY 3 MONTHS OF SHOPIFY FOR $1/MONTH SPECIAL OFFER: ENJOY 3 MONTHS OF SHOPIFY FOR $1/MONTH

Custom modal attachment files send an email on the product view page in Magento 2

Today will show you how to Custom modal attachment files send an email on the product view page in Magento 2.

I. The files need to add.

We need to add items and files.

  1. [VendorName]/[ModuleName]/registration.php
  2. [VendorName]/[ModuleName]/etc/module.xml
  3. [VendorName]/[ModuleName]/etc/frontend/routes.xml
  4. [VendorName]/[ModuleName]/Controller/Index/Index.php
  5. [VendorName]/[ModuleName]/Controller/Index/Post.php
  6. [VendorName]/[ModuleName]/Model/Mail/Template/TransportBuilder.php
  7. [VendorName]/[ModuleName]/etc/di.xml
  8. [VendorName]/[ModuleName]Block/Index/Index.php
  9. [VendorName]/[ModuleName]/view/frontend/layout/catalog_product_view.xml
  10. [VendorName]/[ModuleName]/view/frontend/templates/customemail_index_index.phtml
  11. [VendorName]/[ModuleName]/etc/email_templates.xml
  12. [VendorName]/[ModuleName]/view/frontend/js/example-modal.js
  13. [VendorName]/[ModuleName]/view/frontend/requirejs-config.js
  14. [VendorName]/[ModuleName]/view/frontend/email/customemail.html

II: Create a new module

1.create [VendorName]/[ModuleName]/registration.php :

<?php

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

2.Next create file [VendorName]/[ModuleName]/etc/module.xml

<?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="Magepow_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>

3.Next create file [VendorName]/[ModuleName]/etc/frontend/routes.xml

<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="Magepow_Customemail" />
</route>
</router>
</config>

4. Create file [VendorName]/[ModuleName]/Controller/Index/Index.php

<?php

namespace Magepow\Customemail\Controller\Index;

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

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

5. [VendorName]/[ModuleName]/Controller/Index/Post.php

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

use Zend\Log\Filter\Timestamp;
use Magento\MediaStorage\Model\File\UploaderFactory;
use Magento\Framework\Filesystem\Io\File;
use Magento\Framework\Filesystem;
use Magento\Framework\App\Filesystem\DirectoryList;

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';
const FOLDER_LOCATION = 'contactattachment';
protected $_inlineTranslation;
protected $_transportBuilder;
protected $_scopeConfig;
protected $_logLoggerInterface;
private $fileUploaderFactory;
private $fileSystem;

public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\Translate\Inline\StateInterface $inlineTranslation,
\Magepow\Customemail\Model\Mail\Template\TransportBuilder $transportBuilder,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Psr\Log\LoggerInterface $loggerInterface,
UploaderFactory $fileUploaderFactory,
File $file,
Filesystem $fileSystem,
array $data = []

)
{
$this->_inlineTranslation = $inlineTranslation;
$this->_transportBuilder = $transportBuilder;
$this->_scopeConfig = $scopeConfig;
$this->_logLoggerInterface = $loggerInterface;
$this->messageManager = $context->getMessageManager();
$this->fileUploaderFactory = $fileUploaderFactory;
$this->file = $file;
$this->fileSystem = $fileSystem;

parent::__construct($context);


}

public function execute()
{
$post = $this->getRequest()->getPostValue();
try
{

$filePath = null;
$fileName = null;
$uploaded = false;

try {
$fileCheck = $this->fileUploaderFactory->create(['fileId' => 'attachment']);
$file = $fileCheck->validateFile();
$attachment = $file['name'] ?? null;
} catch (\Exception $e) {
$attachment = null;
}

if ($attachment) {
$upload = $this->fileUploaderFactory->create(['fileId' => 'attachment']);
$upload->setAllowRenameFiles(true);
$upload->setFilesDispersion(true);
$upload->setAllowCreateFolders(true);
$upload->setAllowedExtensions(['txt', 'csv', 'jpg', 'jpeg', 'gif', 'png', 'pdf', 'doc', 'docx']);
$path = $this->fileSystem
->getDirectoryRead(DirectoryList::MEDIA)
->getAbsolutePath(self::FOLDER_LOCATION);
$result = $upload->save($path);
$uploaded = self::FOLDER_LOCATION . $upload->getUploadedFilename();
$filePath = $result['path'] . $result['file'];
$fileName = $result['name'];
}

/** @see \Magento\Contact\Controller\Index\Post::validatedParams() */
$replyToName = !empty($variables['data']['name']) ? $variables['data']['name'] : null;
$mimeType = mime_content_type($filePath);

$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',$storeScope);

$sentToName = $this->_scopeConfig ->getValue('trans_email/ident_general/name',$storeScope);

$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'],
'message' => $post['message']
])
->setFrom($sender)
->addTo($sentToEmail,$sentToName)
->createAttachment($this->file->read($filePath), $fileName, $mimeType)
->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;
}

}
}

6. [VendorName]/[ModuleName]/Model/Mail/Template/TransportBuilder.php

<?php
namespace Magepow\Customemail\Model\Mail\Template;
use Magento\Framework\App\TemplateTypesInterface;
class TransportBuilder extends \Magento\Framework\Mail\Template\TransportBuilder
{
protected $message;
protected $_attachment;
protected $_parts = [];
/**
* Add an attachment to the message.
*
* @param string $content
* @param string $fileName
* @param string $fileType
* @return $this
*/
public function getAttachment($content, $fileName, $fileType)
{
$attachment = new \Zend\Mime\Part($content);
$attachment->type = $fileType;
$attachment->disposition = \Zend_Mime::DISPOSITION_ATTACHMENT;
$attachment->encoding = \Zend_Mime::ENCODING_BASE64;
$attachment->filename = $fileName;
return $attachment;
}
/**
* Prepare message.
*
* @return $this
* @throws LocalizedException if template type is unknown
*/
protected function prepareMessage()
{
$template = $this->getTemplate();
$body = $template->processTemplate();
switch ($template->getType()) {
case TemplateTypesInterface::TYPE_TEXT:
$textPart = new \Zend\Mime\Part();
$textPart->setContent($body)
->setType(\Zend\Mime\Mime::TYPE_TEXT)
->setCharset('utf-8')
;
$this->_parts[] = $textPart;
break;
case TemplateTypesInterface::TYPE_HTML:
$htmlPart = new \Zend\Mime\Part();
$htmlPart->setContent($body)
->setType(\Zend\Mime\Mime::TYPE_HTML)
->setCharset('utf-8')
;
$this->_parts[] = $htmlPart;
break;
default:
throw new LocalizedException(
new Phrase('Unknown template type')
);
}
parent::prepareMessage();
$this->setPartsToBody();
return $this;
}
public function createAttachment($content, $fileName, $fileType) {
if($fileType === null) $fileType = 'image/jpeg,image/gif,image/png,application/pdf,image/x-eps';
$disposition = \Zend\Mime\Mime::DISPOSITION_ATTACHMENT;
$encoding = \Zend\Mime\Mime::ENCODING_BASE64;
if($fileName === null) throw new \Exception("Param 'filename' can not be null");
$attachmentPart = new \Zend\Mime\Part();
$attachmentPart
->setContent($content)
->setType($fileType)
->setDisposition($disposition)
->setEncoding($encoding)
->setFileName($fileName)
;
$this->_attachment = $attachmentPart;
return $this;
}
public function setPartsToBody() {
if($this->_attachment) $this->_parts[] = $this->_attachment;
$mimeMessage = new \Zend\Mime\Message();
$mimeMessage->setParts($this->_parts);
$this->message->setBody($mimeMessage);
return $this;
}
}

7. Create file [VendorName]/[ModuleName]/etc/di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- Mail sending with attachment -->
<preference for="\Magento\Framework\Mail\Template\TransportBuilder" type="Magepow\Customemail\Model\Mail\Template\TransportBuilder" />
</config>

8. Next create file [VendorName]/[ModuleName]Block/Index/Index.php

<?php

namespace Magepow\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();
}

}

9. [VendorName]/[ModuleName]/view/frontend/layout/catalog_product_view.xml

<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="product.info.main">
<block class="Magepow\Customemail\Block\Index\Index" name="customemail_index_index" template="Magepow_Customemail::customemail_index_index.phtml"
before="product.info.extrahint"/>
</referenceBlock>
<referenceContainer name="sidebar.additional">
<referenceBlock name="wishlist_sidebar" remove="true"/>
<referenceBlock name="catalog.compare.sidebar" remove="true"/>
<referenceBlock name="sale.reorder.sidebar" remove="true"/>
</referenceContainer>
<move element="page.main.title" destination="product.info.main" before="-"/>
<referenceContainer name="content">
<container name="product.view" htmlTag="div" htmlClass="product-view" before="-">
<container name="product.inner" htmlTag="div" htmlClass="row main-inner" before="-">
<container name="product.media.wrapper" htmlTag="div" htmlClass="product-media-wrapper col-xl-5 col-lg-5">
<container name="product.info.media" htmlTag="div" htmlClass="product media" />
</container>
<container name="product.main.wrapper" htmlTag="div" htmlClass="product-main-wrapper col-xl-7 col-lg-7">
<container name="product.info.main" htmlTag="div" htmlClass="product-info-main">
<container name="row.product.info.main" htmlTag="div" htmlClass="row row-primary">
<container name="col.product.info.main.left" htmlTag="div" htmlClass="product-left col-xl-6 col-lg-6">
<container name="inside.col.product.info.main.left" htmlTag="div" htmlClass="inside-product-left">
<block class="Magento\Catalog\Pricing\Render" name="product.price.tier" after="product.info.price">
<arguments>
<argument name="price_render" xsi:type="string">product.price.render.default</argument>
<argument name="price_type_code" xsi:type="string">tier_price</argument>
<argument name="zone" xsi:type="string">item_view</argument>
</arguments>
</block>
<container name="alert.urls" as="alert_urls" label="Alert Urls" after="product.price.tier"/>
<block class="Magento\Catalog\Block\Product\View" name="product.info" template="Magento_Catalog::product/view/form.phtml" after="alert.urls">
<container name="product.info.form.content" as="product_info_form_content">
<block class="Magento\Catalog\Block\Product\View" name="product.info.addtocart" as="addtocart" template="Magento_Catalog::product/view/addtocart.phtml"/>
</container>
<block class="Magento\Framework\View\Element\Template" name="product.info.form.options" as="options_container">
<block class="Magento\Catalog\Block\Product\View" name="product.info.options.wrapper" as="product_options_wrapper" template="Magento_Catalog::product/view/options/wrapper.phtml">
<block class="Magento\Catalog\Block\Product\View\Options" name="product.info.options" as="product_options" template="Magento_Catalog::product/view/options.phtml">
<block class="Magento\Catalog\Block\Product\View\Options\Type\DefaultType" name="product.info.options.default" as="default" template="Magento_Catalog::product/view/options/type/default.phtml"/>
<block class="Magento\Catalog\Block\Product\View\Options\Type\Text" name="product.info.options.text" as="text" template="Magento_Catalog::product/view/options/type/text.phtml"/>
<block class="Magento\Catalog\Block\Product\View\Options\Type\File" name="product.info.options.file" as="file" template="Magento_Catalog::product/view/options/type/file.phtml"/>
<block class="Magento\Catalog\Block\Product\View\Options\Type\Select" name="product.info.options.select" as="select" template="Magento_Catalog::product/view/options/type/select.phtml"/>
<block class="Magento\Catalog\Block\Product\View\Options\Type\Date" name="product.info.options.date" as="date" template="Magento_Catalog::product/view/options/type/date.phtml"/>
</block>
<block class="Magento\Framework\View\Element\Html\Calendar" name="html_calendar" as="html_calendar" template="Magento_Theme::js/calendar.phtml"/>
</block>
<block class="Magento\Catalog\Block\Product\View" name="product.info.options.wrapper.bottom" as="product_options_wrapper_bottom" template="Magento_Catalog::product/view/options/wrapper/bottom.phtml">
<block class="Magento\Catalog\Block\Product\View" name="product.info.addtocart.additional" as="product.info.addtocart" template="Magento_Catalog::product/view/addtocart.phtml"/>
</block>
</block>
</block>
<container name="product.info.extrahint" as="extrahint" label="Product View Extra Hint">
<container name="product.info.social" label="Product social links container" htmlTag="div" htmlClass="product-social-links">
<block class="Magento\Catalog\Block\Product\View" name="product.info.addto" as="addto" template="Magento_Catalog::product/view/addto.phtml">
<block class="Magento\Catalog\Block\Product\View\AddTo\Compare" name="view.addto.compare" after="view.addto.wishlist"
template="Magento_Catalog::product/view/addto/compare.phtml" >
<arguments>
<argument name="addToCompareViewModel" xsi:type="object">Magento\Catalog\ViewModel\Product\Checker\AddToCompareAvailability</argument>
</arguments>
</block>
</block>
<block class="Magento\Catalog\Block\Product\View" name="product.info.mailto" template="Magento_Catalog::product/view/mailto.phtml"/>
</container>
</container>
<block class="Magento\Catalog\Block\Product\View\Description" name="product.info.overview" template="Magento_Catalog::product/view/attribute.phtml" group="detailed_info" after="product.info.extrahint">
<arguments>
<argument name="at_call" xsi:type="string">getShortDescription</argument>
<argument name="at_code" xsi:type="string">short_description</argument>
<argument name="css_class" xsi:type="string">overview</argument>
<argument name="at_label" xsi:type="string">none</argument>
<argument name="title" translate="true" xsi:type="string">Overview</argument>
<argument name="add_attribute" xsi:type="string">itemprop="description"</argument>
</arguments>
</block>
</container>
</container>
<container name="col.product.info.main.right" htmlTag="div" htmlClass="product-right col-xl-6 col-lg-6">
<container name="inside.col.product.info.main.right" htmlTag="div" htmlClass="inside-product-right">
<container name="product.info.price" label="Product info auxiliary container" htmlTag="div" htmlClass="product-info-price">
<container name="product.info.stock.sku" label="Product auxiliary info" htmlTag="div" htmlClass="product-info-stock-sku">
<container name="product.info.type" before="-"/>
<block class="Magento\Catalog\Block\Product\View\Description" name="product.info.sku" template="Magento_Catalog::product/view/attribute.phtml" after="product.info.type">
<arguments>
<argument name="at_call" xsi:type="string">getSku</argument>
<argument name="at_code" xsi:type="string">sku</argument>
<argument name="css_class" xsi:type="string">sku</argument>
<argument name="at_label" xsi:type="string">default</argument>
<argument name="add_attribute" xsi:type="string">itemprop="sku"</argument>
</arguments>
</block>
</container>
<block class="Magento\Catalog\Block\Product\View" name="product.info.review" template="Magento_Catalog::product/view/review.phtml" after="product.info.stock.sku" />
<block class="Magento\Catalog\Pricing\Render" name="product.price.final">
<arguments>
<argument name="price_render" xsi:type="string">product.price.render.default</argument>
<argument name="price_type_code" xsi:type="string">final_price</argument>
<argument name="zone" xsi:type="string">item_view</argument>
</arguments>
</block>
</container>
</container>

</container>
</container>
</container>
</container>
</container>
</container>
</referenceContainer>
<move element="page.main.title" destination="inside.col.product.info.main.left" before="-"/>
</body>
</page>

10. Next create [VendorName]/[ModuleName]/view/frontend/templates/customemail_index_index.phtml

<div class="get-quote-box">
<button href="javascript:" data-reveal-id="getQuoteForm" class="button get-free-quote expand round" id="get-free-quote">
<span class="ti ti-pencil-alt"></span>
<span>Get Quote &amp; Preview</span>
</button>
<button type="button" title="Buy Sample" id="product-addtocart-button-one" class="button btn-buy-sample expand round">
<span class="wrp">
<span class="ti-image">
</span> <span class="txt">Buy Sample</span>
</span>
</button>
</div>
<div id="getQuoteForm" style="display: none" class="reveal-modal tiny open" data-reveal="" aria-labelledby="modalTitle" aria-hidden="false" role="dialog" style="display: block; opacity: 1; visibility: visible; top: 464px;" tabindex="0">
<h2 id="modalTitle"><span class="ti ti-gallery"></span> Get Free Quote &amp; Preview</h2>
<a class="close-reveal-modal" aria-label="Close"><i class="ti ti-close"></i></a>
<div class="info-area">
<p><span class="ti ti-info-alt"></span><?= $block->
escapeHtmlAttr(__('end a photo of your wall and expect a preview from us soon. You can also specify your special requests. If everything is ok, you can place order.')) ?></p>
</div>
<form name="quoteForm" id="quoteForm" action="<?php echo $block->getBaseUrl().'customemail/index/post/';?>" enctype="multipart/form-data" method="post">
<fieldset class="fieldset">
<div class="row">
<div class="field large-12 required">
<label class="label" for="title"><span><?= $block->
escapeHtmlAttr(__('Name')) ?></span></label>
<input name="name" id="name" title="Name" value="" class="input-text" type="text"
required="true">
</div>
<div class="field large-12 required">
<label class="label" for="title"><span><?= $block->
escapeHtmlAttr(__('Email')) ?></span></label>
<input name="email" id="email" title="Email" value="" class="input-text" type="text"
placeholder="yout@email.com" required="true">
</div>
<div class="large-12">
<label class="label" for="title"><span><?= $block->escapeHtmlAttr(__('Message')) ?></span></label>
<textarea name="message" id="message" rows="5" placeholder="Dimensions of your wall, special requirements..." required="true"></textarea>
</div>
<div class="field large-12 required">
<input type="file" name="attachment" id="attachment" class="inputfile" data-multiple-caption="{count} files selected" accept="image/jpeg,image/gif,image/png,application/pdf,image/x-eps" multiple="" value="" required="true">
<div class="info-area">
<span class="small tip"><span class="ti ti-info-alt"></span><?= $block->escapeHtmlAttr(__('If you send your space photos, we can prepare a preview with your design')) ?></span>
</div>
</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>
</div> <script>
require(['jquery', 'Magento_Ui/js/modal/modal'],
function ($, modal) {
var modaloption = {
type: 'popup',
modalClass: 'modal-popup',
responsive: true,
innerScroll: true,
clickableOverlay: true
};
$("#get-free-quote").on("click", function (){
var callforoption = modal(modaloption, $('#getQuoteForm'));
$('#getQuoteForm').modal('openModal');
})
}
);
</script>

11.Next ctreate file [VendorName]/[ModuleName]/etc/email_templates.xml

<?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="Magepow_Customemail" area="frontend"/>
</config>

12. Next create file [VendorName]/[ModuleName]/view/frontend/js/example-modal.js

define([
    "jquery", "Magento_Ui/js/modal/modal"
], function($){
    var ExampleModal = {
        initModal: function(config, element) {
            $target = $(config.target);
            $target.modal();
            $element = $(element);
            $element.click(function() {
                $target.modal('openModal');
            });
        }
    };
    return {
        'example-modal': ExampleModal.initModal
    };
}
);

13.Next create file [VendorName]/[ModuleName]/view/frontend/requirejs-config.js

var config = { map: { '*': { 'example-modal': 'Magepow_CustomModal/js/example-modal' } } };

14. Final create file [VendorName]/[ModuleName]/view/frontend/email/customemail.html

{{template config_path="design/email/header_template"}}
<table class="message-details">
<tr>
<td><strong>{{trans "Name:"}}</strong></td>
<td>{{var name}}</td>
</tr>
<tr>
<td><strong>{{trans "Email:"}}</strong></td>
<td>{{var email}}</td>
</tr>
</table>
<p><strong>{{trans "Message:"}}</strong></p>
<p>{{var message}}</p>
{{layout handle="email_product_list" products=$collectionProduct area="frontend"}}
{{template config_path="design/email/footer_template"}}

III. Running command

Run the “setup:upgrade” command

Running this command makes your new module active, notifying Magento of its presence.

php bin/magento setup:upgrade

next running this command deploy:

php bin/magento setup:static-content:deploy -f

Next to running this command delete cache:

php bin/magento cache:flsuh

Hope this article will help you in some way. You can see useful articles in the next articles.