Skip to content

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 the sampleEmailData() / 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

RouteControllerMethodHTTPDescription
settings/email_viewsAdvEmailViewerindex()GETBrowse and preview all email templates
settings/email_views/editEmailSubjectsAdvEmailViewereditEmailSubjects()GET/POSTEdit 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:9allowRole([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:3templateFolder = "main/mail"). These are what Adv_mailer actually renders at email-send time.

FilePurpose
apologize_shipping_delay.phpDelivery-delay apology notice; layout orderInformDelay (emailViews.json:53-55); consumed by sendCustomerInformDelay() (Adv_mailer.php:456)
ask_us_email.phpLegacy "ask us" form — orphan, only referenced by the viewer's hard-coded list
birthday_wishes.phpBirthday greetings + optional loyalty points
blog_comment_accept.phpBlog comment moderation — approved notification
blog_comment_reject.phpBlog comment moderation — rejected notification
contact_email.phpDefault contact-form email
contact_email_generated.phpGeneric contact-form email via generated form config (fullSampleForm)
email_products_summary.phpComponent included by other templates via componentView('emailProductsSummary') (emailViews.json:75-79)
gift_card.phpGift card delivery to recipient
gift_card_inform_customer.phpGift card purchase confirmation to buyer
notify_admin.phpAdmin order notification
notify_admin_low_stock.phpAdmin low-stock alert
notify_admin_new_product.phpAdmin new-product notification (inform_new_product() flagged @todo ... BROKEN ATM at Adv_mailer.php:272, method body Adv_mailer.php:273)
order_created.phpCustomer order confirmation
order_on_store.php"Your order arrived at the store"
order_update.phpOrder status update (shipping / paid / invoiced)
product_review_accept.phpReview moderation — approved notification
product_review_reject.phpReview moderation — rejected notification
remaining_points.phpLoyalty "you have remaining points" reminder
reset_password.phpPassword reset with encrypted token
return_form.phpReturn-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.phpPost-purchase review prompt for Facebook
review_for_google.phpPost-purchase review prompt for Google
review_for_skroutz.phpPost-purchase review prompt for Skroutz
waiting_list_success.phpBack-in-stock notification

Two Mail Directories

There are two mail view directories, and they have drifted apart:

DirectoryFile CountReader
application/views/main/mail/25Adv_mailer (runtime sends) — driven by emailViews.json::templateFolder = "main/mail"
application/views/default/mail/17AdvEmailViewer (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 (layout contactEmailGenerated)
  • apologize_shipping_delay (layout orderInformDelay) — file exists in main/mail/ and resolves fine at runtime; simply not offered for preview
  • return_form (layout returnEmail, NEW) — same: exists in main/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 KeyConsumer in application/models/Adv_mailer.php
contactForm / fullSampleFormNot 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_RESETrecover_password_mail() L74
ORDER_COMPLETEorder_complete() L170
ORDER_UPDATEorder_has_been_updated() L209
WAITING_LISTsendEmailForWaitingList() L267
ORDER_ON_STOREorder_is_on_store() L347
USER_REVIEW_ACCEPTsendUserReviewStatusUpdateEmail() L407
USER_REVIEW_REJECTsendUserReviewStatusUpdateEmail() L407
REVIEW_FOR_FACEBOOKsendCustomerPromptReview() L421
REVIEW_FOR_SKROUTZsendCustomerPromptReview() L424
REVIEW_FOR_GOOGLEsendCustomerPromptReview() L427
CUSTOMER_INFORM_DELAYsendCustomerInformDelay() L461
REMAINING_POINTSsentRemainingPoints() L509
BIRTHDAY_WISHESsentBirthdayWishes() L542
GIFT_CARDsendGiftCardToEmailRenderer() L588 (view) / L598 (doSend)
GIFT_CARD_INFORM_CUSTOMERsendGiftCardToEmailRenderer() L587 (view) / L597 (doSend)
BLOG_COMMENT_ACCEPTsendBlogCommentStatusUpdateEmail() L618
BLOG_COMMENT_REJECTsendBlogCommentStatusUpdateEmail() 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_productAdv_mailer::sendAdmin() falls back to getRegistryValue('TITLE', 'SITE', ...) at Adv_mailer.php:686, or uses $data['subject'] (set from the site.emails.inform_new_product.title lang line at Adv_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

ComponentPathPurpose
AdvEmailViewerecommercen/settings/controllers/AdvEmailViewer.phpAdmin controller (230 lines)
Email_viewsapplication/modules/settings/controllers/Email_views.phpHMVC entry point, thin subclass of AdvEmailViewer
Adv_mailerapplication/models/Adv_mailer.phpRuntime mailer (771 lines, Adv_base_model)
Mailerecommercen/core/Mailer.phpPHPMailer wrapper (SMTP only)
Advisable\Template\Templatesrc/Template/Template.phpResolves layouts / components via emailViews.json
Advisable\Template\Configsrc/Template/Config.phpLoads template JSON config
Email views configapplication/config/emailViews.jsonLayout and component mappings (80 lines, 23 layouts)
Default subject seedsapplication/config/db_default_values.php:42 (keys L43-151)Baseline EMAIL_SUBJECTS values
Subject seederdatabase/seeders/InitialSeed.php:8569-8580Inserts defaults into registry
FormsConfigapplication/modules/forms/libraries/FormsConfig.phpEmpty subclass of AdvFormsConfig
AdvFormsConfigecommercen/forms/libraries/AdvFormsConfig.phpLoads application/config/contact_forms.php, exposes getContactFormKeys(), getContactFormKeysDropDown(), getEmailTemplateView(), etc. — not a list of email templates
ExternalLangecommercen/libraries/ExternalLang.phpPer-locale string resolver passed to every template
Admin menuapplication/config/admin_menu.php:941-954Two entries (email_views L941-947, editEmailSubjects L948-954), gated on [AUTH_ROLE_ADVISABLE, AUTH_ROLE_ADMIN]
Viewer templateapplication/views/admin/settings/email_views.phpIterates $email_views and loads each (:24)
Subject editor viewapplication/views/admin/settings/email_subjects.phpRenders 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):

  1. Seeds empty defaults for contact-form keys via FormsConfig::getContactFormKeys().
  2. 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") at AdvEmailViewer.php:208 — see Known Issues #5.
        • Calls $this->registry->setValue('EMAIL_SUBJECTS', $postKey, $postValue, $langAbbr) at AdvEmailViewer.php:209.
    • Flashes t('eshop.admin.success.entryedit') and redirects.
  3. 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.php with inputs named {key}_{langAbbr}.

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 GroupKey PatternDescription
EMAIL_SUBJECTS{template_name_or_const}Subject line for each email template, per language
EMAIL_CONTACT_FORMSMTP credentials (8 keys)Transport for contact-form and return-form emails
EMAIL_SHOP_MAILERSMTP credentials (8 keys)Transport for all other emails

Configuration

  • Admin menu: application/config/admin_menu.php:941-954 — two entries (settings/email_views L941-947, settings/email_views/editEmailSubjects L948-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 into emailViews.json + Adv_mailer. Client repos should use custom/ for new modern code, but the legacy mail pipeline still lives under application/.
  • Override controller: Extend AdvEmailViewer via application/modules/settings/controllers/Email_views.php to add client-specific preview entries.
  • Additional subjects: Register client-specific subjects under the EMAIL_SUBJECTS registry group per language.
  • Sample currency override (#422 / 4.115.0): Override sampleCurrencyId() in a client subclass to preview emails with a different currency. Base returns 1 (AdvEmailViewer.php:30-33); used at AdvEmailViewer.php:144-145 via getCurrencyData($this->sampleCurrencyId()). Regression-guarded by tests/Legacy/Settings/AdvEmailViewerHooksTest.php (see Tests).
  • Sample data override (#426): Override sampleEmailData(): array (AdvEmailViewer.php:47-149) to replace the entire base sample-data payload previewed in the email viewer, or override extendSampleEmailData(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): Override loadSampleDataDependencies(): void (protected no-op hook, AdvEmailViewer.php:39-41, called at the end of the private initTestEmailViews() at AdvEmailViewer.php:23) to load extra helpers/models needed by a customized sampleEmailData()/extendSampleEmailData().

Business Rules

  1. Preview-only: The viewer renders emails with synthetic test data — it does not send actual emails.
  2. Per-language subjects: Subjects are stored per language in the registry, allowing full multi-language customization.
  3. Sample data: Test data is Greek-market (names, addresses); it is returned by the overridable sampleEmailData() seam (AdvEmailViewer.php:47-149), not inline in index() or initTestEmailViews().
  4. No in-browser template editing: The viewer shows rendered output only. Template HTML is edited in code, not through the admin UI.
  5. Customer locale wins: At dispatch, the customer's language is preferred over the admin's language for both subject and body.
  6. SMTP only: Mail is sent via PHPMailer over SMTP using one of two credential sets (EMAIL_CONTACT_FORM or EMAIL_SHOP_MAILER).

Known Issues & Security Gaps

  1. 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 :41 throws unless the value is exactly EMAIL_CONTACT_FORM or EMAIL_SHOP_MAILER. This is a stale doc-comment defect only — there is no functional gap, and only two purposes actually exist.
  2. sentBirthdayWishes() logs the wrong email type. Adv_mailer.php:541 passes emailType='REMAINING_POINTS' (apparent copy/paste from sentRemainingPoints()) while the subject used is BIRTHDAY_WISHES (L542). Birthday emails are recorded in customer_message_history under type REMAINING_POINTS instead of BIRTHDAY_WISHES.
  3. addEmailToCustomerHistory() dead null-coalesce (#434, OPEN). Adv_mailer.php:766!empty($emailSubject) ?? 'EMAIL' evaluates !empty(...) to a boolean, which is never null, so ?? 'EMAIL' is dead code and a boolean is passed as the 3rd argument to customer_message_history_model->addRecord(...) (L763-769, 5 args).
  4. inform_new_product() flagged BROKEN yet still wired. Adv_mailer.php:272 carries 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 from Adv_products_admin.php:280, 736.
  5. rtrim character-mask bug in the subject editor. AdvEmailViewer.php:208 strips the language suffix with rtrim($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.
  6. Viewer / runtime template-directory divergence. The viewer reads application/views/default/mail/ (app.php:19 sets the deprecated client_views = 'default') while Adv_mailer reads application/views/main/mail/ (emailViews.json:3). 5 viewer-listed templates fail to load from default/: birthday_wishes, blog_comment_accept, blog_comment_reject, gift_card_inform_customer, remaining_points.
  7. Viewer $email_views list incomplete. AdvEmailViewer.php:166-188 omits 3 real standalone templates known to emailViews.json: contact_email_generated, apologize_shipping_delay, return_form. Admins cannot preview any of the three.
  8. Orphan ask_us_email.php. Present in both mail directories and in the viewer's list (AdvEmailViewer.php:167) but has no emailViews.json layout, no EMAIL_SUBJECTS key, and no Adv_mailer caller. Dead code preserved only for viewer rendering.
  9. Blog-comment emails logged as USER_REVIEW. sendBlogCommentStatusUpdateEmail() passes emailType='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 #422 sampleCurrencyId() client-override seam: asserts the method exists, is protected, non-static, returns int, and takes zero args (L34-41); asserts it returns 1 by default (L44-52); asserts it is overridable by a subclass returning 2 (L54-76). Uses newInstanceWithoutConstructor() on an anonymous subclass to avoid the Admin_c bootstrap.
  • tests/Unit/Domains/Customer/Customer/PasswordResetServiceTest.php and tests/Integration/Domains/Customer/Customer/PasswordResetServiceIntegrationTest.php — cover the PasswordResetService caller contract (mocks recover_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.


  • 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_reject via sendUserReviewStatusUpdateEmail()
  • SY-11 Review Reminders — sends review_for_facebook / _skroutz / _google via sendCustomerPromptReview()
  • SY-15 Delivery Delay — sends apologize_shipping_delay (orderInformDelay layout) apology emails via sendCustomerInformDelay()
  • 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 AuthPasswordResetService is the live caller of recover_password_mail()
  • CF-29 Contact Forms — dispatches contact_email / contact_email_generated / return_form via sendContactFormEmail() / sendReturnFormEmail()