What you will learn

Build a fictional service-enquiry form that prepares an email for the project owner. Start with a free local preview, then study an optional paid-send path with clear consent and duplicate-click handling. The deliverable is a reviewed notification flow with honest status messages, not a bulk email system or a customer mailing list.

Understand the fixed recipient and the cost first

Gammal Tech’s notification contract exposes GammalTech.notify(subject, html). It always targets the project owner’s verified email. There is no recipient argument for a visitor’s address, no arbitrary to, cc or from, and no login requirement for the visitor. Requests still use the registered-domain model. The service retains a monitored copy; include that destination in your client’s data review.

As published on 12 October 2026, each delivered email costs 0.40 EGP with no free allowance. Funding the wallet is separate from assigning balance to the project. Complete the local preview without paying. An actual send is optional and requires the owner’s approval and available project funds. For client work, the client controls their own project and account; never request shared login credentials.

Create a small form using fictional content

Use two approved enquiry types and a short fictional message. Do not collect an identity document, session token, payment information or sensitive customer record.

<label for="service">Fictional enquiry type</label>
<select id="service">
  <option value="website-review">Website review</option>
  <option value="training">Training</option>
</select>
<label for="message">Fictional message (10-500 characters)</label>
<textarea id="message" maxlength="500"></textarea>
<button id="preview" type="button">Preview without sending</button>
<pre id="notification-preview"></pre>
<label><input id="cost-consent" type="checkbox">
  I approve one paid owner notification.
</label>
<button id="send" type="button">Optional paid send</button>
<p id="notification-status" role="status"></p>

Place the supporting JavaScript after these elements in your own exercise file. Explain the price beside the optional send controls in the real page. The checkbox records a deliberate local action; it is not a trusted authorization system. For a preview-only submission, omit the optional send handler and do not load the SDK.

Validate the choices and escape the visitor text

Use a fixed subject and a small allowlist of enquiry types. The following builder escapes visitor text before placing it inside a fixed HTML paragraph. OWASP’s output-handling guidance explains why the intended output context matters.

const service = document.getElementById("service");
const message = document.getElementById("message");
const status = document.getElementById("notification-status");
const preview = document.getElementById("notification-preview");
const escapeHtml = value => value.replace(/[&<>"']/g, c => ({
  "&": "&amp;", "<": "&lt;", ">": "&gt;",
  '"': "&quot;", "'": "&#39;"
}[c]));
function buildNotification() {
  const choices = { "website-review": "Website review", training: "Training" };
  if (!Object.hasOwn(choices, service.value)) throw new Error();
  const text = message.value.trim();
  if (text.length < 10 || text.length > 500) throw new Error();
  return {
    subject: "Learning lab: fictional service enquiry",
    html: "<p>Type: " + choices[service.value] + "</p><p>"
      + escapeHtml(text) + "</p>"
  };
}
document.getElementById("preview").addEventListener("click", () => {
  try {
    const draft = buildNotification();
    preview.textContent = draft.subject + "\n" + draft.html;
    status.textContent = "Local preview only. No email sent.";
  } catch {
    preview.textContent = "";
    status.textContent = "Check the enquiry type and message length.";
  }
});

Gammal Tech documents service-side HTML sanitization, but your application should still construct a narrow message format. Escaping here is for text inside the paragraph, not arbitrary HTML attributes, URLs or scripts. Preview the prepared HTML as literal text so it cannot become executable page markup.

Finish the no-cost acceptance exercise first

Notification preview tests that send no email
CaseExpected resultEvidence
Approved type and 10 to 500 charactersA fixed subject and a prepared messageLocal preview screenshot
A note containing <b>demo</b>Encoded characters in the prepared HTMLNo bold user content in the preview
Missing or very short messageValidation message and empty previewNo prepared request
An unapproved type supplied locallyBuilder rejectionNo subject or body sent

Use fictional wording such as “Please discuss a training website next week.” Your preview proves message construction; it does not prove delivery. Mark the live-send result “not executed” when you stop here.

Add one explicit paid-send path if authorized

For an optional live exercise, deploy to your registered HTTPS domain, load the documented SDK before this handler and keep the earlier builder in scope:

<script src="https://api.gammal.tech/sdk-web.js"></script>
const send = document.getElementById("send");
const consent = document.getElementById("cost-consent");
send.addEventListener("click", async () => {
  if (send.disabled) return;
  if (!consent.checked) {
    status.textContent = "Owner approval and cost consent required.";
    return;
  }
  let draft;
  try { draft = buildNotification(); }
  catch {
    status.textContent = "Check the enquiry type and message length.";
    return;
  }
  send.disabled = true;
  status.textContent = "Submitting one request.";
  try {
    const accepted = await GammalTech.notify(draft.subject, draft.html);
    status.textContent = accepted === true
      ? "Accepted for delivery. Check the owner’s inbox."
      : "Delivery request not confirmed. Check before trying again.";
  } catch {
    status.textContent = "Request not confirmed. Check before trying again.";
  }
  // Remain disabled until the owner checks the result.
});

The return value true means accepted for delivery. It does not mean the owner has read the message. The button remains disabled after the request, including an uncertain outcome, pending an owner check. There is no application retry loop. Do not change the catch branch to send another notification reporting its own failure.

Explain what the interface does not enforce

The documented limits are 10 notifications per hour per visitor and 120 per hour per project. These are provider limits, while your short fields and disabled button are local interface behavior. A person can change browser code or reload the page, so the button is not a complete abuse-prevention mechanism.

Keep a named owner responsible for reviewing expected volume and project spending. A worksheet can estimate delivered-notification cost as delivered count multiplied by 0.40 EGP; 25 delivered notifications would cost 10 EGP under the stated rate. Other services are excluded. If the intended workflow needs a broader messaging or customer-email system, assess that requirement separately rather than misrepresenting this fixed-recipient function.

Define useful alerts and uncertain outcomes

A notification helps route a request; it is not authority for sensitive decisions. A message saying “payment complete” is not proof of payment; a visitor can write those words. Do not grant access, dispatch goods or change administrator permissions because of the message body.

Write a short operator note: which subject identifies the learning exercise, who checks the mailbox, and what happens if the request is not confirmed. Avoid claiming guaranteed delivery time or inventing a delivery-status endpoint. When checking an optional live result, record the owner’s confirmation without copying their mailbox contents or credentials into your portfolio.

Hand over a clear notification worksheet

Submit the form, builder, preview results, cost calculation and a state diagram in words: draft, invalid, ready, submitting, accepted or uncertain. Add the live-send status honestly, including “not executed” when appropriate. Explain the fixed recipient and why your code has no email-address field.

Acceptance requires escaped visitor text, bounded inputs, clear cost awareness, no automatic repeat send and messages that distinguish acceptance from confirmed receipt. List the project owner and support process by role rather than private account details.

Common questions

Can this API email any customer address?

No. The documented notify function sends only to the project owner’s verified email. It is not a general-purpose bulk mail or visitor auto-reply API.

Must I pay to complete the lesson?

No. The local builder and preview complete the core exercise without sending. A live notification is optional, requires approval and costs 0.40 EGP per delivered email at the stated date.

Lesson references

Documentation checked on 12 October 2026. Recheck current documentation before implementing or quoting a client project.

Start your Gammal Tech exercise

Read the lesson, then practise with fictional data on a site you own or are authorized to use. Use your own verified individual account and open Developer Mode to configure your project. While awaiting verification, start with the data map and test plan.

Back to Articles & Guides