A marketing proposal template you can write with AI and send as a link

Copy the sample proposal, ask an AI to fill it from your own facts, check every price, and send one link. The client opens it in a browser with no account, and your later fixes reach the same address.

A marketing proposal template is a page with the same few sections every time: the client's goal, what you will do, the timeline, the price, and how to accept.

The quickest route for a freelancer is to copy a sample, let an AI fill it from your facts, check the numbers, and send it as one link.

Sending the proposal is where it gets messy. One solo professional who shares AI-made analysis described the routine: "export to PDF, email the attachment, and field replies by email. Every revision is a new attachment. Nobody is sure which version is current."

Here is a sample you can copy. Press a package and tick an add-on to see the total change. Every name and number is made up, so replace them with yours.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Marketing proposal: Harbor and Pine Coffee</title>
<style>
  * { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui, sans-serif; color: #1d2330; background: #f4f5f7; line-height: 1.55; }
  .page { max-width: 720px; margin: 0 auto; padding: 22px 18px 30px; background: #fff; }
  .tag { display: inline-block; font-size: 12px; font-weight: 700; letter-spacing: .4px; color: #9a3412; background: #ffedd5; border-radius: 999px; padding: 2px 10px; }
  h1 { font-size: 26px; line-height: 1.2; margin: 10px 0 6px; }
  .meta { color: #5b6473; font-size: 14px; margin: 0 0 16px; }
  .sum { background: #eff6ff; border-radius: 10px; padding: 12px 14px; margin: 0 0 6px; }
  .sum b { color: #1d4ed8; }
  h2 { font-size: 18px; margin: 24px 0 6px; }
  p { margin: 0 0 10px; }
  ul { padding-left: 20px; margin: 0; }
  li { margin-bottom: 5px; }
  .pk { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 8px 0 12px; }
  .pk button { font: inherit; text-align: left; padding: 10px 12px; border-radius: 10px; border: 1px solid #c9ceda; background: #fff; cursor: pointer; }
  .pk button b { display: block; font-size: 15px; }
  .pk button span { font-size: 13px; color: #5b6473; }
  .pk button[aria-pressed="true"] { border-color: #1d4ed8; background: #eff6ff; box-shadow: 0 0 0 1px #1d4ed8; }
  .add { display: block; margin: 0 0 6px; font-size: 15px; }
  .add input { margin-right: 8px; }
  .total { margin-top: 12px; padding: 12px 14px; border-radius: 10px; background: #f0fdf4; border: 1px solid #bbf7d0; display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
  .total b { font-size: 22px; color: #0f5132; }
  .note { font-size: 13px; color: #5b6473; border-left: 3px solid #d5d9e0; padding-left: 10px; margin-top: 10px; }
  .accept { margin-top: 22px; padding: 12px 14px; border-radius: 10px; background: #fff7ed; border: 1px solid #fed7aa; }
  footer { margin-top: 18px; padding-top: 12px; border-top: 1px solid #e5e7eb; font-size: 14px; color: #374151; }
  @media (max-width: 480px) { h1 { font-size: 22px; } .pk { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<main class="page">
  <span class="tag">SAMPLE - replace every name and number with yours</span>
  <h1>Marketing proposal: spring launch for Harbor and Pine Coffee</h1>
  <p class="meta">Prepared by Fieldnote Studio (made-up) - valid until 30 November 2026 - version 1</p>

  <div class="sum">
    <p><b>The goal.</b> Get more people to try the new seasonal menu in the first month after it opens.</p>
    <p><b>What we will do.</b> Plan the launch, write and design the content, and report what happened.</p>
    <p style="margin:0"><b>What it costs.</b> From the amount in the choice box below, depending on the package.</p>
  </div>

  <h2>Scope: what is included</h2>
  <ul>
    <li>One planning call and a written launch plan.</li>
    <li>Launch posts, an email to the existing list, and a poster for the counter.</li>
    <li>A short report at the end, with the numbers you can check yourself.</li>
  </ul>

  <h2>Choose a package</h2>
  <p>Press a package, then tick any add-ons. The total changes as you go. Nothing is sent or saved.</p>
  <div class="pk" role="group" aria-label="Packages">
    <button type="button" data-p="starter" aria-pressed="true"><b>Starter</b><span>6 posts, 1 email</span></button>
    <button type="button" data-p="growth" aria-pressed="false"><b>Growth</b><span>12 posts, 2 emails, poster</span></button>
    <button type="button" data-p="full" aria-pressed="false"><b>Full launch</b><span>20 posts, 3 emails, poster, report</span></button>
  </div>
  <label class="add"><input type="checkbox" data-a="photo"> Photo styling day (sample 400)</label>
  <label class="add"><input type="checkbox" data-a="ads"> Ad set-up, two weeks (sample 350)</label>
  <div class="total" aria-live="polite">
    <span id="pname">Starter package</span>
    <b id="ptotal">1,200</b>
  </div>
  <p class="note">All amounts are invented sample figures in one currency. Say what is not included, such as ad spend or printing.</p>

  <h2>Timeline</h2>
  <ul>
    <li><b>Week 1:</b> planning call, launch plan agreed.</li>
    <li><b>Weeks 2 to 3:</b> content drafted and sent to you for comments.</li>
    <li><b>Week 4:</b> publish, then a short report.</li>
  </ul>

  <div class="accept">
    <b>To accept:</b> reply to the email that came with this link, saying which package and add-ons you want. This page does not collect signatures or payments.
  </div>

  <footer>Fieldnote Studio - hello@example.com</footer>
</main>

<script>
  const packages = {
    starter: { name: 'Starter package', price: 1200 },
    growth: { name: 'Growth package', price: 2100 },
    full: { name: 'Full launch package', price: 3400 }
  };
  const addons = { photo: 400, ads: 350 };
  let current = 'starter';

  function render() {
    let total = packages[current].price;
    document.querySelectorAll('[data-a]').forEach((box) => {
      if (box.checked) total += addons[box.dataset.a];
    });
    document.getElementById('pname').textContent = packages[current].name;
    document.getElementById('ptotal').textContent = total.toLocaleString('en-US');
    document.querySelectorAll('[data-p]').forEach((b) => {
      b.setAttribute('aria-pressed', String(b.dataset.p === current));
    });
  }

  document.querySelectorAll('[data-p]').forEach((b) => {
    b.addEventListener('click', () => { current = b.dataset.p; render(); });
  });
  document.querySelectorAll('[data-a]').forEach((box) => box.addEventListener('change', render));
  render();
</script>
</body>
</html>
A sample marketing proposal with three packages and two add-ons. The visitor's choices are not saved or sent.

What goes in a marketing proposal

Keep the order the same each time, so you can reuse the page for the next client. The reader should be able to stop after the first screen and still know what you are offering.

  • Goal. One or two sentences in the client's own words.
  • Scope. What is included, and what is not, such as ad spend or printing.
  • Packages. Two or three options with one price each.
  • Timeline and payments. Weeks, not vague promises.
  • How to accept. One plain sentence, such as replying to your email.

Make it with AI

An AI is good at turning rough facts into a tidy page. It is also willing to fill gaps with plausible numbers, so the prompt has to forbid that.

Anthropic's documentation on reducing hallucinations suggests letting the model say it does not have enough information, and restricting it to documents you provide. It adds that these techniques do not eliminate hallucinations.

Paste the prompt below into ChatGPT, Claude or Gemini and replace the facts at the bottom.

Turn my facts into a marketing proposal as ONE self-contained HTML file.

Rules:
- Use only the facts below. Do not invent prices, dates, results, clients or guarantees.
- If something is missing, write [ADD: what is missing] instead of guessing.
- Sections in order: Goal, What I will do, What is not included, Packages (with prices), Timeline, How to accept.
- Plain HTML and CSS. It must work on a phone. No external images, scripts or forms.
- Under 500 words.

My facts:
Client and what they want:
Services and deliverables:
Not included:
Packages and prices:
Start date, weeks, payment dates:
Valid until:

Then check the result before it goes anywhere:

  • Prices and dates. Match each one to your own notes.
  • Promises. Remove any result or guarantee you did not write.
  • [ADD] marks. Fill each one with a fact, or delete the sentence.
  • Names. Use the client's name as they spell it, and leave out other clients.
  • Phone. Narrow your browser window, or ask for a viewport meta tag. See viewport meta tag.

A file attached to an email is a copy you cannot fix once it is sent. A link is one page you can still correct. Proposal link covers why that suits a proposal that gets passed around.

The route from your facts to an AI draft, your check, and a share link.
The route from your facts to an AI draft, your check, and a share link.
  1. Copy the whole HTML the AI gave you.
  2. Paste it into a NOS document. The page renders as written.
  3. Click any wording you want to improve and type. Editing HTML without coding explains this step.
  4. Choose Create share link. HTML to link walks through it.
  5. Paste the link into your email.

Whoever opens it sees the page in a browser, on a phone or a laptop, with no account to create. They cannot edit it. The sample's package buttons work for the client too, but what they tick is not saved for you.

On a phone, an attached HTML file has to be downloaded and opened. A link opens as a page.
On a phone, an attached HTML file has to be downloaded and opened. A link opens as a page.

If you change a price later, you edit the text and the same link shows the new version. A form that sends data to a server is blocked, so the client says yes by replying to your email.

Anyone with the link can open the page, so leave out private data. If you are unsure how an attached file opens on a phone, read opening an HTML file on a phone.

Ways to send a proposal compared

An attachment multiplies copies with every change. A link stays one page.
An attachment multiplies copies with every change. A link stays one page.
Attach the .html file Attach a PDF Share link
What the client needs To download and open the file To download and open the file A browser, no account
Fixing a price later Send a new file Send a new file Edit the text, same link
Copies in circulation One per message or forward One per message or forward One page
Email size limit Counts toward it Counts toward it A link is a line of text

As of October 2026, Gmail's help says the attachment limit is 25 MB, and that Gmail adds a Google Drive link when the total is larger. A link avoids the question. Other mail services set their own limits.

Add a timeline and payment page

Clients often ask when the money is due. A second sample shows the same idea: pick a project length, and the bars and the payment dates follow.

Live exampletry it here, then copy the code
Share it as a link
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Timeline and payments</title>
<style>
  * { box-sizing: border-box; }
  body { margin: 0; padding: 16px 14px 24px; font-family: system-ui, sans-serif; color: #1d2330; background: #fff; line-height: 1.5; }
  .wrap { max-width: 680px; margin: 0 auto; }
  .tag { display: inline-block; font-size: 12px; font-weight: 700; color: #9a3412; background: #ffedd5; border-radius: 999px; padding: 2px 10px; }
  h1 { font-size: 22px; margin: 8px 0 4px; line-height: 1.2; }
  p { margin: 0 0 10px; color: #374151; }
  .toggle { display: flex; gap: 8px; margin: 12px 0; }
  .toggle button { font: inherit; font-size: 14px; padding: 6px 14px; border-radius: 999px; border: 1px solid #c9ceda; background: #fff; cursor: pointer; }
  .toggle button[aria-pressed="true"] { background: #1d4ed8; border-color: #1d4ed8; color: #fff; }
  .bars { display: grid; gap: 8px; margin: 6px 0 16px; }
  .row { display: grid; grid-template-columns: 110px 1fr; align-items: center; gap: 10px; font-size: 14px; }
  .track { position: relative; height: 22px; background: #f3f4f6; border-radius: 6px; }
  .bar { position: absolute; top: 0; bottom: 0; background: #93c5fd; border-radius: 6px; }
  table { width: 100%; border-collapse: collapse; font-size: 14px; }
  th, td { text-align: left; padding: 8px 8px; border-bottom: 1px solid #e5e7eb; }
  th { color: #5b6473; font-weight: 600; }
  td.amt { text-align: right; white-space: nowrap; }
  .note { font-size: 13px; color: #5b6473; margin-top: 10px; }
  @media (max-width: 480px) { .row { grid-template-columns: 84px 1fr; font-size: 13px; } }
</style>
</head>
<body>
<div class="wrap">
  <span class="tag">SAMPLE - replace with your own plan</span>
  <h1>Timeline and payments</h1>
  <p>Choose how long the work should take. The bars and the payment dates follow.</p>
  <div class="toggle" role="group" aria-label="Project length">
    <button type="button" data-w="4" aria-pressed="true">4 weeks</button>
    <button type="button" data-w="8" aria-pressed="false">8 weeks</button>
  </div>

  <div class="bars" id="bars"></div>

  <table>
    <thead><tr><th>Payment</th><th>When</th><th class="amt">Share</th></tr></thead>
    <tbody id="pay"></tbody>
  </table>
  <p class="note" id="note"></p>
</div>

<script>
  const plans = {
    4: {
      tasks: [['Plan', 0, 1], ['Draft', 1, 2], ['Review', 3, 1], ['Publish', 3, 1]],
      pay: [['Deposit', 'Week 1', '50%'], ['Final', 'Week 4', '50%']],
      note: 'Four weeks, two payments. Tasks overlap in the last week.'
    },
    8: {
      tasks: [['Plan', 0, 2], ['Draft', 2, 3], ['Review', 5, 1], ['Publish', 6, 2]],
      pay: [['Deposit', 'Week 1', '30%'], ['Midpoint', 'Week 4', '40%'], ['Final', 'Week 8', '30%']],
      note: 'Eight weeks, three payments. A midpoint payment follows the first drafts.'
    }
  };
  const bars = document.getElementById('bars');
  const pay = document.getElementById('pay');

  function show(weeks) {
    const p = plans[weeks];
    bars.innerHTML = '';
    p.tasks.forEach(([name, start, len]) => {
      const row = document.createElement('div');
      row.className = 'row';
      const label = document.createElement('span');
      label.textContent = name;
      const track = document.createElement('div');
      track.className = 'track';
      const bar = document.createElement('div');
      bar.className = 'bar';
      bar.style.left = (start / weeks * 100) + '%';
      bar.style.width = (len / weeks * 100) + '%';
      track.appendChild(bar);
      row.append(label, track);
      bars.appendChild(row);
    });
    pay.innerHTML = '';
    p.pay.forEach((r, i) => {
      const tr = document.createElement('tr');
      r.forEach((cell, j) => {
        const td = document.createElement('td');
        td.textContent = cell;
        if (j === 2) td.className = 'amt';
        tr.appendChild(td);
      });
      pay.appendChild(tr);
    });
    document.getElementById('note').textContent = p.note;
    document.querySelectorAll('[data-w]').forEach((b) => {
      b.setAttribute('aria-pressed', String(b.dataset.w === String(weeks)));
    });
  }

  document.querySelectorAll('[data-w]').forEach((b) => {
    b.addEventListener('click', () => show(Number(b.dataset.w)));
  });
  show(4);
</script>
</body>
</html>
Choose 4 or 8 weeks. The task bars and the payment table change. Replace the sample plan with yours.

Ask the AI to build this from your own dates and splits, then check the percentages add up to 100. For more ideas on price pages, see HTML for pricing sheets.

When it does not work

What you see Cause Fix
Prices you never gave The AI filled a gap Re-run with "use only my facts", then compare line by line
A logo or photo is missing The image is hosted elsewhere, and outside images are blocked Ask for inline SVG or CSS shapes
A "send" button does nothing Sending a form to a server is blocked Add "reply to my email to accept"
A font or script is missing It loads from a site that is not allowed Use Google Fonts, cdnjs, jsDelivr, unpkg or no extras
Text is tiny on a phone No viewport meta tag Ask the AI to add one
The client sees an old price They opened a copy you attached earlier Send the link, and edit the page from then on

Questions people ask

What should a marketing proposal template include?

The goal in the client's words, what you will do, what is not included, a timeline, the price or packages, and how to say yes. Put the goal and the price near the top so the first screen answers the main questions.

Can I let an AI write the whole proposal?

Let it draft and format from facts you give it, and treat the result as a draft. Anthropic's guidance on reducing hallucinations says its techniques reduce them but do not eliminate them, so you check every price, date and claim yourself.

Can the client accept on the page?

Not with a signature or a payment. A form that sends data to a server is blocked on a NOS page. Add a line such as "To accept, reply to my email with your package", and keep the real agreement in the document you normally use.

Does the client need an account to open the link?

No. A NOS share link opens in a browser on a phone or a laptop without an account, and the visitor cannot edit the page.

What if I change the price after sending it?

Edit the text in your own document and the same link shows the new version. Add a dated line such as "Version 2, price updated" so the client can see what changed.

Keep reading