etchflow / module-order-email-editor
Admin module to edit the customer email on a placed sales order, with optional customer-record sync and an audit history. Hyva / Magento Open Source / Adobe Commerce compatible.
Package info
github.com/Hamza-khan09/etechflow_OrderEmailEditor
Type:magento2-module
pkg:composer/etchflow/module-order-email-editor
Requires
- php: ~8.1.0||~8.2.0||~8.3.0||~8.4.0
- magento/framework: >=103.0.0
- magento/module-backend: >=102.0.0
- magento/module-customer: >=103.0.0
- magento/module-sales: >=103.0.0
- magento/module-ui: >=101.0.0
README
Magento 2 admin module that lets an admin edit the customer email address on a placed order, optionally sync the change to the linked customer account, and keep an audit history of every change.
Compatible with:
- Magento Open Source 2.4+
- Adobe Commerce 2.4+
- Hyvä themes — the module is admin-only, so it has zero impact on Hyvä's stripped-down storefront. No RequireJS, no Knockout, no jQuery used by this module on any page.
Features
| Edit misspelled email on a placed order | ✓ |
| Update both billing + shipping address rows on the order | ✓ |
| Auto-reindex Magento's order/invoice/shipment/creditmemo grid tables | ✓ (via core observer on sales_order_save_after) |
Optionally update the linked customer_entity.email |
✓ (checkbox, disabled for guest orders) |
| Defensive quote-table sync if the original quote still exists | ✓ |
| Audit log of every change with admin user, IP, timestamp | ✓ |
| Standard Magento ACL — granular per-role permissions | ✓ |
| No frontend dependencies (admin-only module) | ✓ |
Installation
Option A — Composer (recommended for production)
composer require etechflow/module-order-email-editor:^1.0 bin/magento module:enable Etechflow_OrderEmailEditor bin/magento setup:upgrade bin/magento setup:di:compile # production mode only bin/magento setup:static-content:deploy -f en_GB # production mode only bin/magento cache:flush
Option B — Manual drop-in
- Copy the whole
Etechflow_OrderEmailEditorfolder toapp/code/Etechflow/OrderEmailEditor/. - Run:
bin/magento module:enable Etechflow_OrderEmailEditor bin/magento setup:upgrade bin/magento setup:di:compile # production mode only bin/magento cache:flush
The setup:upgrade step creates one new database table: etechflow_email_change_history.
Permissions (ACL)
Two new resources appear under System → Permissions → User Roles → Role Resources → Sales → Operations → Orders:
Etechflow_OrderEmailEditor::edit_email— required to use the modal & POST to the update endpointEtechflow_OrderEmailEditor::view_history— required to view the history grid
By default both are granted to "All" / Admin role. Assign them granularly to limited roles as needed.
Usage
- Admin → Sales → Orders → pick any order.
- In the Order & Account Information panel you'll see an Edit Email button under the existing email.
- Click it. A modal opens with:
- Current email shown for confirmation
- New email input
- "Also update the linked customer account" checkbox (hidden for guest orders)
- Submit. The modal returns a success message, the email on the page updates inline, and a new row is written to
etechflow_email_change_history.
Viewing change history
Admin → Sales → Operations → Order Email Change History (or the URL /admin/order_email_editor/history/index).
Standard Magento UI Component grid with filterable columns: increment ID, old email, new email, admin who changed it, customer-record-updated flag, IP, timestamp.
What this module touches in the database
When the Change Email button is clicked, the module updates these tables in a single transaction:
| Table | Column | How |
|---|---|---|
sales_order |
customer_email |
via OrderRepository::save() (clean) |
sales_order_address |
email (both billing + shipping rows) |
via OrderRepository::save() |
sales_order_grid |
customer_email |
auto (Magento's sales_order_save_after observer reindexes) |
sales_invoice_grid |
customer_email |
auto, same observer |
sales_creditmemo_grid |
customer_email |
auto, same observer |
sales_shipment_grid |
customer_email |
auto, same observer |
customer_entity |
email |
only if checkbox is on AND sales_order.customer_id is set |
quote + quote_address |
customer_email / email |
defensive — only if the original quote row still exists |
etechflow_email_change_history |
new row | inserted with old/new email, admin info, IP |
customer_grid_flat is rebuilt automatically by the customer indexer after the customer save.
Uninstall
bin/magento module:disable Etechflow_OrderEmailEditor # Optionally drop the history table: mysql -e "DROP TABLE IF EXISTS etechflow_email_change_history" $DB # If installed via Composer: composer remove etechflow/module-order-email-editor rm -rf app/code/Etechflow/OrderEmailEditor # if installed manually bin/magento setup:upgrade bin/magento cache:flush
Why this module is Hyvä-safe
Hyvä themes only replace the storefront — admin is untouched. This module has:
- No
view/frontend/directory - No
requirejs-config.js - No
data-mage-init, notext/x-magento-init, norequire([...]), no jQuery, no Knockout, no Magento UI Component on the storefront - Pure server-rendered admin templates + vanilla JS (
fetch()) for the AJAX call
The admin UI uses standard Magento UI Components and admin layout XML — no Hyvä-specific patterns required.
Compatibility matrix
| Platform | Status |
|---|---|
| Magento Open Source 2.4.4 – 2.4.8 | ✓ tested patterns |
| Adobe Commerce 2.4.4 – 2.4.8 | ✓ (no commerce-only dependencies used) |
| Hyvä child theme (any version) | ✓ (admin-only module) |
| PHP 8.1 / 8.2 / 8.3 / 8.4 | ✓ (uses readonly constructor-promoted properties; composer.json pins `~8.1 |
| MySQL 8 / MariaDB 10.6+ | ✓ |
Verification (sanity check after install)
-- 1. Module enabled? SELECT * FROM core_config_data WHERE path='setup_version' AND value LIKE '%OrderEmailEditor%'; -- 2. History table exists? SHOW TABLES LIKE 'etechflow_email_change_history'; -- 3. After editing one order via the UI, check audit row: SELECT * FROM etechflow_email_change_history ORDER BY changed_at DESC LIMIT 5; -- 4. Verify the order email is updated everywhere: SET @oid = <your order_id>; SELECT customer_email FROM sales_order WHERE entity_id = @oid; SELECT email FROM sales_order_address WHERE parent_id = @oid; SELECT customer_email FROM sales_order_grid WHERE entity_id = @oid; SELECT customer_email FROM sales_invoice_grid WHERE order_id = @oid;
Module file layout
Etechflow_OrderEmailEditor/
├── registration.php
├── composer.json
├── LICENSE
├── README.md
├── etc/
│ ├── module.xml
│ ├── db_schema.xml
│ ├── di.xml
│ ├── acl.xml
│ └── adminhtml/
│ ├── routes.xml
│ └── menu.xml
├── Api/
│ ├── Data/EmailChangeHistoryInterface.php
│ └── EmailChangeHistoryRepositoryInterface.php
├── Model/
│ ├── EmailChangeHistory.php
│ ├── EmailChangeHistoryRepository.php
│ ├── ResourceModel/EmailChangeHistory.php
│ ├── ResourceModel/EmailChangeHistory/Collection.php
│ ├── ResourceModel/EmailChangeHistory/Grid/Collection.php
│ ├── Service/UpdateOrderEmail.php
│ └── Source/YesNo.php
├── Controller/
│ └── Adminhtml/
│ ├── Order/Update.php # POST /admin/order_email_editor/order/update
│ └── History/Index.php # GET /admin/order_email_editor/history/index
├── view/
│ └── adminhtml/
│ ├── layout/
│ │ ├── sales_order_view.xml
│ │ └── order_email_editor_history_index.xml
│ ├── ui_component/
│ │ └── order_email_editor_history_listing.xml
│ ├── templates/
│ │ └── order/view/edit-email.phtml
│ └── web/
│ ├── css/edit-email.css
│ └── js/edit-email.js
└── i18n/
└── en_GB.csv
License
MIT — see LICENSE.