What a template is for
The message you have typed from memory more than ten times. Save it once, pick it whenever you need it, and it arrives with each person's own details filled in.
Picking a template into a message copies the text. Editing the template afterwards changes nothing you have already written from it, which is what you want — the alternative silently rewrites a message somebody already approved, possibly one that has been queued for a week.

Filling in each person's details
Templates use Liquid, the same syntax as Shopify and Mailchimp, so most of what you already know works.
{{ contact.name }} fills in their name. {{ contact.name | default: "there" }} says "there" for the people you have no name for — worth doing, because a message that begins "Hi ," is the sort of thing a customer notices.
{% if contact.first_name %}…{% endif %} includes a whole phrase only when you have the value, and filters like | upcase change how a value is written.
{{ contact.first_name }} and {{ contact.last_name }} split their name, and anything stored on the contact as a custom field fills in as {{ contact.custom.<name> }}. The same variables work in announcements, scheduled messages and automation steps, filled in when each message sends.
Hi {{ contact.name | default: "there" }}, a reminder about your appointment tomorrow at {{ contact.custom.appointment_time | default: "the usual time" }}.
See what it will actually say
The preview under the message box is rendered by the same code that sends it, so what you see is what goes out. It also counts how often each variable is empty across the people you are actually sending to.
"contact.name is empty for 38 of 412 people" is a decision you can make; "contact.name may be empty" is not. Add a fallback fills in the filter for you.

If a template will not save
A template that cannot be read is refused when you save it, with the problem in one line. That is deliberate: a broken template discovered at send time has no good outcome, because printing the raw text to a customer is worse than not sending at all.
The usual cause is an unclosed tag — {% if %} with no {% endif %}.