Skip to content

Email info CRUD and linking

clsEmailAddressInfo is a standalone EMAIL_ADDRESS row with a configurable validation model: callers choose both how strict the check is (syntax only vs. syntax-and-DNS) and how a failure is treated (warning vs. error). As with addresses, the owning collection tracks adds/removes and reconciles the COMPANY_EMAIL / PERSON_EMAIL link rows on save.

Field Value
Operation ID OP-CC-06
Trigger Caller adds/removes a clsEmailAddressInfo in clsCustomer.Emails or clsContact.Emails, then the parent's Save() cascades into the collection; or mdlCustomerContact.CreateEmail is called directly
Inputs Value (email address text), EmailCode (email type), IsPrimary, EmailAddressValidation (Warn/Error), EmailValidationType (None/Syntax/SyntaxAndDNS)
Outputs Persisted EMAIL_ADDRESS row; persisted or removed COMPANY_EMAIL / PERSON_EMAIL link row; IsVerified flag reset on value change
Primary components clsEmailAddressInfo.Create, clsEmailAddressInfo.OnValueChange, clsEmailAddressInfo.AddBusinessRules, mdlCustomerContact.CreateEmail, clsInfoCollection.Save
Entry point Business\SAIF.Business.CustomerContact\InfoItems\clsEmailAddressInfo.vb

Steps

  1. Create a new email row. Create() assigns the row's EmailAddressID from GetNextSeqNum.
  2. Value-change side effect (BR-010). OnValueChange calls the base handler, then unconditionally sets IsVerified = False — any edit to the email text invalidates prior verification.
  3. Configure the validation model (BR-006). Setting EmailAddressValidation (Warn or Error) rebuilds the rule set via AddBusinessRules(), which clears existing rules and registers:
  4. Required check: ValidateEmailRequiredError (level one) if EmailAddressValidation = Error, or ValidateEmailRequiredWarning if Warn.
  5. Syntax check (level two, only if EmailValidationType = Syntax): ValidateEmailSyntaxError/ValidateEmailSyntaxWarning, backed by clsEmailAddress.IsValidEmailAddressSyntax(...).
  6. Syntax-and-DNS check (level two, only if EmailValidationType = SyntaxAndDNS): ValidateEmailSyntaxAndDNSError/ValidateEmailSyntaxAndDNSWarning, backed by clsEmailAddress.IsValidEmailAddress(...).
  7. Persist the root EMAIL_ADDRESS row. Insert (SQL-014/SQL-015), update (SQL-071/SQL-072), and delete (SQL-088/SQL-089) against EMAIL_ADDRESS.
  8. Reconcile link rows through clsInfoCollection.Save(), in the same add/remove-tracking pattern used for addresses (see Address info CRUD and linking): save current email rows, delete removed link rows (customer: SQL-085 against COMPANY_EMAIL; contact: SQL-079 against PERSON_EMAIL), then insert added link rows (customer: SQL-011; contact: SQL-005).
  9. Helper factory flow. mdlCustomerContact.CreateEmail(dpi, contact, address, isPrimary, emailType):
  10. Creates clsEmailAddressInfo.NewEmailAddress(dpi).
  11. Forces EmailAddressValidation = ValidationLevel.Error regardless of caller preference.
  12. Sets IsPrimary and Value.
  13. Resolves EmailCode from mdlCodeMaps.GetEmailTypes(dpi)(emailType).Code.
  14. Adds the new email directly to contact.Emails unconditionally — unlike the phone helper (CreatePhone), it does not gate the add on IsValid.
  15. Resolve the email-type description. EmailTypeDescription calls GetEmailCode(dpi)(EmailCode).Description from the shared SAIF.Business code-map module for display purposes only.

Process flow

The following diagram visualizes email validation configuration and the save/link cycle.

flowchart TD
    Start([Caller sets Value on clsEmailAddressInfo]) --> Reset[OnValueChange:<br>IsVerified = False]
    Reset --> Config[EmailAddressValidation set:<br>rebuild rules via AddBusinessRules]
    Config --> Level{ValidationLevel?}
    Level -->|Error| ReqError[Register required-error rule]
    Level -->|Warn| ReqWarn[Register required-warning rule]
    ReqError --> TypeCheck{EmailValidationType?}
    ReqWarn --> TypeCheck
    TypeCheck -->|Syntax| SyntaxRule[Register syntax rule]
    TypeCheck -->|SyntaxAndDNS| DnsRule[Register syntax+DNS rule]
    TypeCheck -->|None| NoRule[No format rule registered]
    SyntaxRule --> ParentSave
    DnsRule --> ParentSave
    NoRule --> ParentSave
    ParentSave([Parent Save cascades to collection]) --> SaveRows[Save each current EMAIL_ADDRESS row]
    SaveRows --> DeleteLinks[Delete link rows for RemovedItems]
    DeleteLinks --> InsertLinks[Insert link rows for AddedItems]
    InsertLinks --> Done([Collection persisted])

Failure and edge-case behavior

  • With EmailAddressValidation = Error and a required/syntax/DNS failure, the save is blocked by a broken rule; with Warn, the same conditions produce a warning only and do not block the save (BR-006).
  • Any edit to the email Value clears IsVerified, even if the new value is identical in meaning to the old one (for example, only case differs) — verification is not re-derived automatically (BR-010).
  • mdlCustomerContact.CreateEmail adds the new email to the contact's collection before any validation gate is checked, so an invalid address can be added and only surface as a broken rule later, at save time — unlike CreatePhone, which checks IsValid before adding.*
  • Removing an email from a collection deletes only the COMPANY_EMAIL / PERSON_EMAIL link row, not the standalone EMAIL_ADDRESS row.*

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • Business\SAIF.Business.CustomerContact\InfoItems\clsEmailAddressInfo.vb
  • Business\SAIF.Business.CustomerContact\InfoItems\clsInfoCollection.vb
  • Business\SAIF.Business.CustomerContact\Customer\clsCustomerEmailCollection.vb
  • Business\SAIF.Business.CustomerContact\Contact\clsContactEmailCollection.vb
  • Business\SAIF.Business.CustomerContact\mdlCustomerContact.vb