Appearance
Email Template Viewer
Flow ID: AD-53 | Module(s): settings | Complexity: Medium Last Updated: 2026-07-20 — targeted resync for #426: sample data extracted from
index()/initTestEmailViews()into thesampleEmailData()/extendSampleEmailData()/loadSampleDataDependencies()seams; citations and Business Rule #3 updated accordingly
Business Context
The email template viewer provides administrators with a browser for previewing all system email templates. Located at /settings/email_views.htm, it renders each hard-coded template with synthetic Greek-market test data so admins can visually verify email layouts, translations, and content before they reach customers.
The viewer also exposes a subject line editor at /settings/email_views/editEmailSubjects.htm that allows per-language customization of email subject lines via the EMAIL_SUBJECTS registry group. This is the primary way admins change email subjects without touching code.
The viewer hard-codes 21 named template views (ecommercen/settings/controllers/AdvEmailViewer.php:166-188). The real runtime dispatcher Adv_mailer can render a slightly different set — the two lists are out of sync and the underlying template directories have diverged (see Two Mail Directories and Known Issues).
API Reference
REST Endpoints
No REST API. Email template viewing is an admin-only tool.
Legacy Admin Routes
| Route | Controller | Method | HTTP | Description |
|---|---|---|---|---|
settings/email_views | AdvEmailViewer | index() | GET | Browse and preview all email templates |
settings/email_views/editEmailSubjects | AdvEmailViewer | editEmailSubjects() | GET/POST | Edit email subject lines per language |
Routes are HMVC auto-routed through the settings module — no entries in application/config/*routes*.php. The HMVC entry point is a thin subclass: application/modules/settings/controllers/Email_views.php (class Email_views extends AdvEmailViewer {}, 5 lines).
RBAC gate: constructor AdvEmailViewer.php:5-15; the check at AdvEmailViewer.php:9 — allowRole([AUTH_ROLE_ADVISABLE, AUTH_ROLE_ADMIN], $this->sessionRoles) → error_401() on mismatch. One gate covers both viewing and editing.
Code Flow
Template Preview (index)
AdvEmailViewer::index() (ecommercen/settings/controllers/AdvEmailViewer.php:160-197)
|
+--> initTestEmailViews() (private, AdvEmailViewer.php:17-24)
| +--> Loads eshop/order_model, eshop/stores_model, encryption library
| +--> loadSampleDataDependencies() (protected no-op hook, AdvEmailViewer.php:39-41 —
| override point for forks to load extra helpers/models; called at the
| end of initTestEmailViews())
|
+--> $data = extendSampleEmailData($this->sampleEmailData()) (AdvEmailViewer.php:164)
| |
| +--> sampleEmailData() (protected, AdvEmailViewer.php:47-149) builds the base
| | sample-data payload (inline, no external fixtures):
| | - Customer scalars (name, email, phone, address)
| | - orderData array with 25+ keys incl. getCurrencyData(sampleCurrencyId())
| | (sampleCurrencyId() default 1, AdvEmailViewer.php:30-33; used at
| | AdvEmailViewer.php:144-145)
| | - store_data, transporter_name, products, loyalty_reward
| | - store (top-level, mirrors orderData['store'] — consumed by
| | order_on_store to preview the customer-selected pickup store's
| | address/phone/opening_hours, #449)
| | - customerData, token, encryption, giftCard,
| | couponRules, giftCardCoupon
| | - $data['emailViews'] = new Template(
| | new Config(APPPATH . '/config/emailViews.json')
| | ) (AdvEmailViewer.php:131-133; only for
| | views' own component resolution — viewer does NOT use
| | layouts/components to choose which templates to render)
| | - externalLang = new ExternalLang($this->language_abbr) (AdvEmailViewer.php:146)
| |
| +--> extendSampleEmailData(array $data): array (protected no-op hook,
| AdvEmailViewer.php:155-158 — override point for forks to add/override
| sample-data keys)
|
+--> Hard-coded $email_views list (21 entries, AdvEmailViewer.php:166-188):
| ask_us_email, contact_email, notify_admin, notify_admin_low_stock,
| notify_admin_new_product, order_created, order_on_store, order_update,
| product_review_accept, product_review_reject, reset_password,
| review_for_facebook, review_for_skroutz, review_for_google,
| waiting_list_success, remaining_points, birthday_wishes,
| gift_card, gift_card_inform_customer, blog_comment_accept,
| blog_comment_reject
|
+--> view_content = "{$classView}/email_views"
+--> $this->template_view_admin(...)The admin view (application/views/admin/settings/email_views.php:24) iterates $email_views and renders each via:
php
$this->load->view($this->client_views . '/mail/' . $email_view, $data, true)Because application/config/app.php:19 still sets the deprecated $config['client_views'] = 'default', the viewer loads from application/views/default/mail/, not from the directory Adv_mailer actually uses at runtime (application/views/main/mail/, per emailViews.json:3). See Two Mail Directories.
Subject Editor (editEmailSubjects)
AdvEmailViewer::editEmailSubjects() (ecommercen/settings/controllers/AdvEmailViewer.php:199-229)
|
+--> Seed empty defaults for contact form keys:
| $contactFormEmptyData = array_map(
| fn ($item) => '',
| array_flip((new FormsConfig())->getContactFormKeys())
| )
|
+--> On POST ($this->input->post('submit')):
| +--> For each admin language ($this->adminLanguages):
| | +--> For each posted field whose name contains $langAbbr:
| | +--> $postKey = rtrim($postKey, "_$langAbbr") # BUG — AdvEmailViewer.php:208, see Known Issues
| | +--> $this->registry->setValue('EMAIL_SUBJECTS', $postKey, $value, $langAbbr) # AdvEmailViewer.php:209
| +--> Flash success (t('eshop.admin.success.entryedit')), redirect
|
+--> On GET:
| +--> For each admin language:
| | +--> $this->registry->getGroupAsArray('EMAIL_SUBJECTS', $langAbbr)
| | +--> Merge with $contactFormEmptyData as defaults
| +--> Render admin/settings/email_subjects.php with
| inputs named "{key}_{langAbbr}"Domain Layer
No modern domain layer. The email viewer is a pure legacy admin tool.
Templates Directory
Canonical templates live in application/views/main/mail/ (25 files, emailViews.json:3 → templateFolder = "main/mail"). These are what Adv_mailer actually renders at email-send time.
| File | Purpose |
|---|---|
apologize_shipping_delay.php | Delivery-delay apology notice; layout orderInformDelay (emailViews.json:53-55); consumed by sendCustomerInformDelay() (Adv_mailer.php:456) |
ask_us_email.php | Legacy "ask us" form — orphan, only referenced by the viewer's hard-coded list |
birthday_wishes.php | Birthday greetings + optional loyalty points |
blog_comment_accept.php | Blog comment moderation — approved notification |
blog_comment_reject.php | Blog comment moderation — rejected notification |
contact_email.php | Default contact-form email |
contact_email_generated.php | Generic contact-form email via generated form config (fullSampleForm) |
email_products_summary.php | Component included by other templates via componentView('emailProductsSummary') (emailViews.json:75-79) |
gift_card.php | Gift card delivery to recipient |
gift_card_inform_customer.php | Gift card purchase confirmation to buyer |
notify_admin.php | Admin order notification |
notify_admin_low_stock.php | Admin low-stock alert |
notify_admin_new_product.php | Admin new-product notification (inform_new_product() flagged @todo ... BROKEN ATM at Adv_mailer.php:272, method body Adv_mailer.php:273) |
order_created.php | Customer order confirmation |
order_on_store.php | "Your order arrived at the store" |
order_update.php | Order status update (shipping / paid / invoiced) |
product_review_accept.php | Review moderation — approved notification |
product_review_reject.php | Review moderation — rejected notification |
remaining_points.php | Loyalty "you have remaining points" reminder |
reset_password.php | Password reset with encrypted token |
return_form.php | Return-form submission notice; layout returnEmail (emailViews.json:8-10, NEW); consumed by sendReturnFormEmail() (Adv_mailer.php:379); dispatched from Adv_forms.php:136 (shop copy) and :144 (customer copy) |
review_for_facebook.php | Post-purchase review prompt for Facebook |
review_for_google.php | Post-purchase review prompt for Google |
review_for_skroutz.php | Post-purchase review prompt for Skroutz |
waiting_list_success.php | Back-in-stock notification |
Two Mail Directories
There are two mail view directories, and they have drifted apart:
| Directory | File Count | Reader |
|---|---|---|
application/views/main/mail/ | 25 | Adv_mailer (runtime sends) — driven by emailViews.json::templateFolder = "main/mail" |
application/views/default/mail/ | 17 | AdvEmailViewer (admin preview) — driven by deprecated $config['client_views'] = 'default' at application/config/app.php:19 |
Files missing from default/mail/
Present in main/mail/ but not in default/mail/ (8): apologize_shipping_delay, birthday_wishes, blog_comment_accept, blog_comment_reject, contact_email_generated, gift_card_inform_customer, remaining_points, return_form.
Of those, only the ones the viewer actually lists will fail to load at preview time. Viewer-listed and will fail to load from default/ (5): birthday_wishes, blog_comment_accept, blog_comment_reject, gift_card_inform_customer, remaining_points. The remaining three (apologize_shipping_delay, contact_email_generated, return_form) are not in the viewer's $email_views array, so they are never attempted — see below.
Orphan template
ask_us_email.php exists in both directories but is never dispatched at runtime. It has no layout entry in application/config/emailViews.json, no caller in Adv_mailer, and no EMAIL_SUBJECTS.ask_us_email registry key. It survives only because AdvEmailViewer::$email_views (hard-coded, listed at AdvEmailViewer.php:167) lists it for preview.
Templates missing from the viewer's list
The viewer's hard-coded $email_views array (AdvEmailViewer.php:166-188) is missing three layouts that emailViews.json knows about:
contact_email_generated(layoutcontactEmailGenerated)apologize_shipping_delay(layoutorderInformDelay) — file exists inmain/mail/and resolves fine at runtime; simply not offered for previewreturn_form(layoutreturnEmail, NEW) — same: exists inmain/mail/, not offered for preview
The partial email_products_summary is also absent from the list, correctly — it is a component (emailViews.json:75-79), not a standalone preview target.
Subject Registry Keys
Subject strings live in the registry table under the EMAIL_SUBJECTS group, keyed per admin language. Defaults are seeded from application/config/db_default_values.php array email_subject_data (:42, keys L43-151) by database/seeders/InitialSeed.php::emailSubjects() (InitialSeed.php:8569-8580, reggroup='EMAIL_SUBJECTS' at L8576). Edited via AdvEmailViewer::editEmailSubjects() (setValue('EMAIL_SUBJECTS', ...) at AdvEmailViewer.php:209).
| Registry Key | Consumer in application/models/Adv_mailer.php |
|---|---|
contactForm / fullSampleForm | Not consumed by Adv_mailer — read by the contact-forms flow (see CF-29 Contact Forms); call site ecommercen/forms/controllers/Adv_forms.php:60 |
PASSWORD_RESET | recover_password_mail() L74 |
ORDER_COMPLETE | order_complete() L170 |
ORDER_UPDATE | order_has_been_updated() L209 |
WAITING_LIST | sendEmailForWaitingList() L267 |
ORDER_ON_STORE | order_is_on_store() L347 |
USER_REVIEW_ACCEPT | sendUserReviewStatusUpdateEmail() L407 |
USER_REVIEW_REJECT | sendUserReviewStatusUpdateEmail() L407 |
REVIEW_FOR_FACEBOOK | sendCustomerPromptReview() L421 |
REVIEW_FOR_SKROUTZ | sendCustomerPromptReview() L424 |
REVIEW_FOR_GOOGLE | sendCustomerPromptReview() L427 |
CUSTOMER_INFORM_DELAY | sendCustomerInformDelay() L461 |
REMAINING_POINTS | sentRemainingPoints() L509 |
BIRTHDAY_WISHES | sentBirthdayWishes() L542 |
GIFT_CARD | sendGiftCardToEmailRenderer() L588 (view) / L598 (doSend) |
GIFT_CARD_INFORM_CUSTOMER | sendGiftCardToEmailRenderer() L587 (view) / L597 (doSend) |
BLOG_COMMENT_ACCEPT | sendBlogCommentStatusUpdateEmail() L618 |
BLOG_COMMENT_REJECT | sendBlogCommentStatusUpdateEmail() L618 |
The same group is also read in application/views/admin/contact_emails/list.php:89.
Templates with no matching registry key
notify_admin,notify_admin_low_stock,notify_admin_new_product—Adv_mailer::sendAdmin()falls back togetRegistryValue('TITLE', 'SITE', ...)atAdv_mailer.php:686, or uses$data['subject'](set from thesite.emails.inform_new_product.titlelang line atAdv_mailer.php:285).ask_us_email— orphan, no subject.
Email Templates Engine
The viewer instantiates a Template object (AdvEmailViewer.php:131-133) to enable email templates to resolve sub-components via $emailViews->componentView(). For detailed information on template resolution via emailViews.json, the Template / Config system, the complete Adv_mailer method catalog, Adv_mailer internals, SMTP credential management, and the PHPMailer transport pipeline, see SY-24 Email Dispatch System — Code Flow and Template System.
Email Transport & SMTP Configuration
For complete information on the Mailer wrapper, SMTP credentials from the registry (EMAIL_CONTACT_FORM, EMAIL_SHOP_MAILER), credential management, and PHPMailer transport internals, see SY-24 Email Dispatch System — PHPMailer Wrapper and Data Model — Registry Groups.
The admin UI for configuring SMTP credentials lives in application/views/admin/settings/email_block.php and ecommercen/settings/controllers/Adv_settings.php:60-180. There is no MailHog, Mailgun, or SendGrid integration — the platform sends pure SMTP.
Localization
The viewer renders templates using new ExternalLang($this->language_abbr) (the admin's UI language). For detailed information on ExternalLang translation resolution, customer locale precedence, and how the runtime dispatch system handles multi-language email content, see SY-24 Email Dispatch System — ExternalLang Translation.
No MUI tables exist for email content — translations live in CI language files via ExternalLang and in registry subject entries.
Dispatch Points
For a complete map of where each template is dispatched from (synchronous callers, asynchronous cron jobs, legacy cronjob controller methods, and the full line numbers), see SY-24 Email Dispatch System — Caller Map.
Architecture
| Component | Path | Purpose |
|---|---|---|
AdvEmailViewer | ecommercen/settings/controllers/AdvEmailViewer.php | Admin controller (230 lines) |
Email_views | application/modules/settings/controllers/Email_views.php | HMVC entry point, thin subclass of AdvEmailViewer |
Adv_mailer | application/models/Adv_mailer.php | Runtime mailer (771 lines, Adv_base_model) |
Mailer | ecommercen/core/Mailer.php | PHPMailer wrapper (SMTP only) |
Advisable\Template\Template | src/Template/Template.php | Resolves layouts / components via emailViews.json |
Advisable\Template\Config | src/Template/Config.php | Loads template JSON config |
| Email views config | application/config/emailViews.json | Layout and component mappings (80 lines, 23 layouts) |
| Default subject seeds | application/config/db_default_values.php:42 (keys L43-151) | Baseline EMAIL_SUBJECTS values |
| Subject seeder | database/seeders/InitialSeed.php:8569-8580 | Inserts defaults into registry |
FormsConfig | application/modules/forms/libraries/FormsConfig.php | Empty subclass of AdvFormsConfig |
AdvFormsConfig | ecommercen/forms/libraries/AdvFormsConfig.php | Loads application/config/contact_forms.php, exposes getContactFormKeys(), getContactFormKeysDropDown(), getEmailTemplateView(), etc. — not a list of email templates |
ExternalLang | ecommercen/libraries/ExternalLang.php | Per-locale string resolver passed to every template |
| Admin menu | application/config/admin_menu.php:941-954 | Two entries (email_views L941-947, editEmailSubjects L948-954), gated on [AUTH_ROLE_ADVISABLE, AUTH_ROLE_ADMIN] |
| Viewer template | application/views/admin/settings/email_views.php | Iterates $email_views and loads each (:24) |
| Subject editor view | application/views/admin/settings/email_subjects.php | Renders per-language subject inputs |
Role of FormsConfig
FormsConfig is purely a contact-form configuration accessor. AdvEmailViewer::editEmailSubjects() uses it only to seed empty defaults:
php
$contactFormEmptyData = array_map(
fn ($item) => '',
array_flip((new FormsConfig())->getContactFormKeys())
);It does not enumerate email templates.
Subject Editor Flow
AdvEmailViewer::editEmailSubjects() (ecommercen/settings/controllers/AdvEmailViewer.php:199-229):
- Seeds empty defaults for contact-form keys via
FormsConfig::getContactFormKeys(). - On POST (
$this->input->post('submit')):- For each admin language in
$this->adminLanguages:- For each posted field whose name contains
$langAbbr:- Strips the language suffix via
rtrim($postKey, "_$langAbbr")atAdvEmailViewer.php:208— see Known Issues #5. - Calls
$this->registry->setValue('EMAIL_SUBJECTS', $postKey, $postValue, $langAbbr)atAdvEmailViewer.php:209.
- Strips the language suffix via
- For each posted field whose name contains
- Flashes
t('eshop.admin.success.entryedit')and redirects.
- For each admin language in
- On GET:
- For each admin language, loads
$this->registry->getGroupAsArray('EMAIL_SUBJECTS', $langAbbr). - Merges with the empty contact-form defaults.
- Renders
admin/settings/email_subjects.phpwith inputs named{key}_{langAbbr}.
- For each admin language, loads
Data Model
No dedicated tables. Email subjects are stored in the registry table under the EMAIL_SUBJECTS group with per-language entries. See Subject Registry Keys for the full list.
| Registry Group | Key Pattern | Description |
|---|---|---|
EMAIL_SUBJECTS | {template_name_or_const} | Subject line for each email template, per language |
EMAIL_CONTACT_FORM | SMTP credentials (8 keys) | Transport for contact-form and return-form emails |
EMAIL_SHOP_MAILER | SMTP credentials (8 keys) | Transport for all other emails |
Configuration
- Admin menu:
application/config/admin_menu.php:941-954— two entries (settings/email_viewsL941-947,settings/email_views/editEmailSubjectsL948-954) gated on[AUTH_ROLE_ADVISABLE, AUTH_ROLE_ADMIN]. - Template config:
application/config/emailViews.json. - Email template file name:
application/config/app.php:15(emailTemplate = 'emailViews.json'). - Client views setting:
application/config/app.php:19($config['client_views'] = 'default', deprecated — source of the viewer/runtime divergence). - Role constants:
application/config/constants.php:99, 101(AUTH_ROLE_ADVISABLE = 1,AUTH_ROLE_ADMIN = 3).
Required roles: AUTH_ROLE_ADVISABLE and AUTH_ROLE_ADMIN. The constructor at AdvEmailViewer.php:5-15 calls allowRole([AUTH_ROLE_ADVISABLE, AUTH_ROLE_ADMIN], $this->sessionRoles) → error_401() on mismatch (gate itself at L9). The admin menu enforces the same set. There is no separation between viewing and editing — both operations share one role gate.
Client Extension Points
- Custom email templates: Client repos can add templates under
application/views/main/mail/and wire them intoemailViews.json+Adv_mailer. Client repos should usecustom/for new modern code, but the legacy mail pipeline still lives underapplication/. - Override controller: Extend
AdvEmailViewerviaapplication/modules/settings/controllers/Email_views.phpto add client-specific preview entries. - Additional subjects: Register client-specific subjects under the
EMAIL_SUBJECTSregistry group per language. - Sample currency override (
#422/ 4.115.0): OverridesampleCurrencyId()in a client subclass to preview emails with a different currency. Base returns1(AdvEmailViewer.php:30-33); used atAdvEmailViewer.php:144-145viagetCurrencyData($this->sampleCurrencyId()). Regression-guarded bytests/Legacy/Settings/AdvEmailViewerHooksTest.php(see Tests). - Sample data override (
#426): OverridesampleEmailData(): array(AdvEmailViewer.php:47-149) to replace the entire base sample-data payload previewed in the email viewer, or overrideextendSampleEmailData(array $data): array(protected no-op hook,AdvEmailViewer.php:155-158) to add or override individual sample-data keys without duplicating the base payload.index()composes them as$data = $this->extendSampleEmailData($this->sampleEmailData())(AdvEmailViewer.php:164). - Extra sample-data dependencies (
#426): OverrideloadSampleDataDependencies(): void(protected no-op hook,AdvEmailViewer.php:39-41, called at the end of the privateinitTestEmailViews()atAdvEmailViewer.php:23) to load extra helpers/models needed by a customizedsampleEmailData()/extendSampleEmailData().
Business Rules
- Preview-only: The viewer renders emails with synthetic test data — it does not send actual emails.
- Per-language subjects: Subjects are stored per language in the registry, allowing full multi-language customization.
- Sample data: Test data is Greek-market (names, addresses); it is returned by the overridable
sampleEmailData()seam (AdvEmailViewer.php:47-149), not inline inindex()orinitTestEmailViews(). - No in-browser template editing: The viewer shows rendered output only. Template HTML is edited in code, not through the admin UI.
- Customer locale wins: At dispatch, the customer's language is preferred over the admin's language for both subject and body.
- SMTP only: Mail is sent via PHPMailer over SMTP using one of two credential sets (
EMAIL_CONTACT_FORMorEMAIL_SHOP_MAILER).
Known Issues & Security Gaps
getDefaultSmtpCredentials()docblock says "3 options" but only 2 are accepted.ecommercen/helpers/registry_helper.php:35— the docblock states "There are 3 options: EMAIL_CONTACT_FORM, EMAIL_SHOP_MAILER" but lists only 2; the guard at:41throws unless the value is exactlyEMAIL_CONTACT_FORMorEMAIL_SHOP_MAILER. This is a stale doc-comment defect only — there is no functional gap, and only two purposes actually exist.sentBirthdayWishes()logs the wrong email type.Adv_mailer.php:541passesemailType='REMAINING_POINTS'(apparent copy/paste fromsentRemainingPoints()) while the subject used isBIRTHDAY_WISHES(L542). Birthday emails are recorded incustomer_message_historyunder typeREMAINING_POINTSinstead ofBIRTHDAY_WISHES.addEmailToCustomerHistory()dead null-coalesce (#434, OPEN).Adv_mailer.php:766—!empty($emailSubject) ?? 'EMAIL'evaluates!empty(...)to a boolean, which is nevernull, so?? 'EMAIL'is dead code and a boolean is passed as the 3rd argument tocustomer_message_history_model->addRecord(...)(L763-769, 5 args).inform_new_product()flagged BROKEN yet still wired.Adv_mailer.php:272carries a/* @todo refactor this is client custom and should not be called BROKEN ATM */comment directly above the method (body at L273), yet it is still invoked fromAdv_products_admin.php:280, 736.rtrimcharacter-mask bug in the subject editor.AdvEmailViewer.php:208strips the language suffix withrtrim($postKey, "_$langAbbr").rtrim's second argument is a character mask, not a literal suffix, so it will over-strip any trailing characters in that set. It happens to work for current keys but is fragile.- Viewer / runtime template-directory divergence. The viewer reads
application/views/default/mail/(app.php:19sets the deprecatedclient_views = 'default') whileAdv_mailerreadsapplication/views/main/mail/(emailViews.json:3). 5 viewer-listed templates fail to load fromdefault/:birthday_wishes,blog_comment_accept,blog_comment_reject,gift_card_inform_customer,remaining_points. - Viewer
$email_viewslist incomplete.AdvEmailViewer.php:166-188omits 3 real standalone templates known toemailViews.json:contact_email_generated,apologize_shipping_delay,return_form. Admins cannot preview any of the three. - Orphan
ask_us_email.php. Present in both mail directories and in the viewer's list (AdvEmailViewer.php:167) but has noemailViews.jsonlayout, noEMAIL_SUBJECTSkey, and noAdv_mailercaller. Dead code preserved only for viewer rendering. - Blog-comment emails logged as
USER_REVIEW.sendBlogCommentStatusUpdateEmail()passesemailType='USER_REVIEW'(Adv_mailer.php:617), identical to the review flow (L406), so blog-comment moderation emails are misclassified in customer history (minor).
Tests
tests/Legacy/Settings/AdvEmailViewerHooksTest.php(78 lines) — exercises the#422sampleCurrencyId()client-override seam: asserts the method exists, isprotected, non-static, returnsint, and takes zero args (L34-41); asserts it returns1by default (L44-52); asserts it is overridable by a subclass returning2(L54-76). UsesnewInstanceWithoutConstructor()on an anonymous subclass to avoid theAdmin_cbootstrap.tests/Unit/Domains/Customer/Customer/PasswordResetServiceTest.phpandtests/Integration/Domains/Customer/Customer/PasswordResetServiceIntegrationTest.php— cover thePasswordResetServicecaller contract (mocksrecover_password_mail, asserts unknown addresses do not call the mailer). These verify the AD-53 caller contract, not the viewer itself.
Coverage gaps: no dedicated tests exercise AdvEmailViewer::index() rendering, the $email_views list, emailViews.json template resolution, default/mail vs main/mail divergence, getDefaultSmtpCredentials(), the Adv_mailer send pipeline (send()/sendAdmin()/doSend()), or editEmailSubjects()'s subject-writing behavior.
Related Flows
- AD-13 Settings — general settings admin where SMTP credentials (
EMAIL_CONTACT_FORM,EMAIL_SHOP_MAILER) are configured - AD-52 Review Moderation — dispatches
product_review_accept/product_review_rejectviasendUserReviewStatusUpdateEmail() - SY-11 Review Reminders — sends
review_for_facebook/_skroutz/_googleviasendCustomerPromptReview() - SY-15 Delivery Delay — sends
apologize_shipping_delay(orderInformDelay layout) apology emails viasendCustomerInformDelay() - SY-24 Email Dispatch — the runtime pipeline (
Adv_mailer+Mailer+ PHPMailer) that delivers the templates previewed here - AD-03 Order Management Admin — order emails are the highest-volume dispatchers
- CF-10 Customer Auth —
PasswordResetServiceis the live caller ofrecover_password_mail() - CF-29 Contact Forms — dispatches
contact_email/contact_email_generated/return_formviasendContactFormEmail()/sendReturnFormEmail()