Free Newsletter for Blogger with Google Forms (No Mailchimp)

Build a free newsletter signup page for Blogger with Google Forms: collect emails in Google Sheets, no Mailchimp, no plugins, matches your theme.

  • Newsletter with Google Forms cover

    A newsletter turns one-time readers into regular ones. You don't need Mailchimp or a paid plugin to start: a free Google Form can collect the emails, and the Areeb theme gives you a ready-made signup page that matches your blog, works in light and dark mode and never leaves the page. This guide sets it up in about ten minutes.

    Why Google Forms

    Google Forms + Areeb pageEmail services (Mailchimp…)
    PriceFree, no subscriber limitFree plans are limited, then paid
    SetupOne form, one pageAccount, audience, embed code
    SpeedNo extra scripts on your pageTheir script (often with jQuery)
    AvailabilityWorks wherever Google worksSome services are blocked on some networks
    Sending emailsYou send them (Gmail, or import later)Built-in campaigns

    Start with Google Forms. When your list grows, export the emails to any email service in one click.

    Create the form

    1. Open Google FormsGo to forms.google.com and start a Blank form.
    2. Name itClick the title and type Newsletter.
    3. Add one questionName the first question Email, keep the type Short answer and turn on Required.
    A blank Google Form
    A new blank form.
    Google Form with the title Newsletter and one Email question
    Title, one Email question, Required on.

    Keep only one question. The page sends the email to it; any extra required question would block the signup.

    Check the settings

    Open the Settings tab and expand Responses. Set Collect email addresses to Do not collect. This way readers never have to sign in to a Google account.

    Google Forms Responses settings with Do not collect email addresses
    Settings › Responses › Do not collect.

    Leave Limit to 1 response off. It forces a Google sign-in and the page can't do that.

    Publish the form

    1. Click PublishThe button is at the top of the form editor.
    2. Check who can answerResponders must be Anyone with the link.
    3. PublishClick Publish in the dialog.
    Publish dialog with responders set to anyone with the link
    Responders: anyone with the link.

    Find the two values

    The page needs two things from your form: its address and the number of the Email question.

    1. Open the pre-filled link toolClick the three-dot menu at the top and choose Get pre-filled link.
    2. Fill in a test emailType test@test.com in the Email question, click Get link, then Copy link.
    3. Read the linkIt looks like the example below.
    Form menu with the Get pre-filled link option
    Three-dot menu › Get pre-filled link.
    https://docs.google.com/forms/d/e/FORM_ID/viewform?usp=pp_url&entry.123456789=test@test.com
    ValueTake from the linkExample
    Form addressReplace everything after FORM_ID/ with formResponsehttps://docs.google.com/forms/d/e/FORM_ID/formResponse
    Email questionThe part that starts with entry.entry.123456789

    Create the newsletter page

    1. New pageIn Blogger, go to Pages › New page and name it Newsletter.
    2. Switch to HTML viewClick the pencil icon at the top left of the editor and choose HTML view.
    3. Paste the codeCopy the code below and paste it into the page.
    4. Put in your two valuesFind data-action and data-field near the middle and replace the examples with your values.
    5. Publish and testOpen the page, enter your email and click Subscribe. A green thank-you appears inside the card.
    <!-- ===== Areeb Newsletter · paste in Blogger page editor (HTML view) =====
         Saves each email to YOUR Google Form (answers land in Google Forms /
         Google Sheets). No Google script on the page: the email is sent in the
         background and a thank-you shows inside the card.
         Colours follow the theme's light / dark mode automatically.
    
         SETUP (2 values in the <form> below):
           1. Google Forms › new form › one "Short answer" question named Email
              (Settings › Responses: do NOT require sign-in).
           2. Three-dot menu › "Get pre-filled link" › type test@test.com in the
              question › "Get link" › copy the link. It looks like:
              https://docs.google.com/forms/d/e/FORM_ID/viewform?usp=pp_url&entry.123456789=test@test.com
           3. data-action = the same address, with "viewform..." replaced by
              "formResponse":  https://docs.google.com/forms/d/e/FORM_ID/formResponse
           4. data-field  = the entry number:  entry.123456789
    
         EDIT FREELY: the title, text, button label, privacy link and the
         three messages in data-ok / data-bad / data-fail.
         Keep the class names (nlp-*). -->
    <style>
    .nlp{--ink:var(--color,light-dark(#001D35,#F3F5F7));--txt:var(--color-body,light-dark(#202124,#CCCCCC));--mut:var(--color-snippet,light-dark(#595959,#A2A2A2));--well:var(--background-input,light-dark(#F7F8F8,#1F1F1F));--edge:var(--color-edge,light-dark(#EFEFEF,#262626));--brand:var(--color-brand,#E4F15F);--on:var(--color-on-brand,#001D35);--r:var(--radius,18px);--head:var(--font-head,'Sora',sans-serif);--card:light-dark(#FFFFFF,#141414);color:var(--txt);line-height:1.6;container-type:inline-size}
    .nlp *{box-sizing:border-box}
    .nlp svg{min-width:0}
    .nlp-card{position:relative;text-align:center;padding:clamp(28px,6cqi,56px) clamp(18px,5cqi,48px);border-radius:calc(var(--r) + 6px);background:var(--well);border:1px solid var(--edge);overflow:hidden;isolation:isolate}
    .nlp-card::before{content:"";position:absolute;inset:-60% 10% auto;height:120%;border-radius:50%;background:radial-gradient(closest-side,color-mix(in srgb,var(--brand) light-dark(45%,16%),transparent),transparent);z-index:-1}
    .nlp-ic{width:60px;height:60px;margin:0 auto 18px;border-radius:18px;background:var(--brand);display:grid;place-items:center}
    .nlp-ic svg{width:28px;height:28px;fill:none;stroke:var(--on);stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
    .nlp h2{margin:0 auto 10px;max-width:20ch;font:800 clamp(1.5rem,1rem + 2.6cqi,2.3rem)/1.2 var(--head);letter-spacing:-.02em;color:var(--ink)}
    .nlp h2 em{font-style:normal;background:linear-gradient(transparent 62%,var(--brand) 0);padding:0 4px}
    .nlp-lead{margin:0 auto;max-width:46ch;color:var(--mut)}
    .nlp-form{display:flex;gap:8px;max-width:30rem;margin:26px auto 0;padding:6px;background:var(--card);border:1px solid var(--edge);border-radius:999px}
    .nlp-form:focus-within{border-color:var(--ink)}
    .nlp-form input[type=email]{flex:1;min-width:0;border:0;background:none;padding:0 16px;font:inherit;color:var(--ink);outline:0}
    .nlp-form button{border:0;border-radius:999px;padding:12px 24px;background:var(--ink);color:var(--card);font:600 .95rem var(--head);cursor:pointer;white-space:nowrap}
    .nlp-form button:disabled{opacity:.6;cursor:wait}
    .nlp-trap{position:absolute;left:-5000px}
    .nlp-msg{max-width:30rem;margin:14px auto 0;padding:10px 16px;border-radius:12px;font-size:.9rem}
    .nlp-msg[hidden]{display:none}
    .nlp-msg.ok{background:light-dark(#E6F6EE,#10291B);color:light-dark(#00703C,#4ADE80)}
    .nlp-msg.bad{background:light-dark(#FFE9ED,#3A1418);color:light-dark(#B3261E,#FF8A8A)}
    .nlp-small{margin:14px 0 0;font-size:.8rem;color:var(--mut)}
    .nlp-small a{color:inherit}
    .nlp-perks{display:flex;flex-wrap:wrap;justify-content:center;gap:10px 22px;margin:22px 0 0;padding:0;list-style:none;font-size:.88rem;color:var(--mut)}
    .nlp-perks li::before{content:"\2713";margin-inline-end:6px;color:var(--ink);font-weight:700}
    @container (max-width:520px){.nlp-form{flex-direction:column;border-radius:18px}.nlp-form input[type=email]{padding:12px}}
    </style>
    
    <div class="nlp">
      <div class="nlp-card">
        <div class="nlp-ic"><svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="3"/><path d="m3 7 9 6 9-6"/></svg></div>
        <h2>Get new guides <em>in your inbox</em></h2>
        <p class="nlp-lead">The best tutorials and news, straight to you. No spam, unsubscribe anytime.</p>
    
        <form class="nlp-form" novalidate
          data-action="https://docs.google.com/forms/d/e/FORM_ID/formResponse"
          data-field="entry.000000000"
          data-ok="Thanks for subscribing! New guides will reach your inbox."
          data-bad="Please enter a valid email address."
          data-fail="Something went wrong. Please try again in a moment.">
          <input type="email" name="email" placeholder="Your email address" aria-label="Email address" autocomplete="email" required>
          <!-- bot trap: real people never fill this hidden field -->
          <input class="nlp-trap" type="text" name="website" tabindex="-1" autocomplete="off" aria-hidden="true">
          <button type="submit">Subscribe</button>
        </form>
        <p class="nlp-msg" role="status" aria-live="polite" hidden></p>
    
        <ul class="nlp-perks">
          <li>New guides first</li>
          <li>One email at a time</li>
          <li>Free, forever</li>
        </ul>
        <p class="nlp-small">By subscribing you agree to our <a href="/p/privacy-policy.html">Privacy policy</a>.</p>
      </div>
    </div>
    
    <script>
    (function () {
      var form = document.querySelector('.nlp-form');
      if (!form) return;
      var msg = form.parentNode.querySelector('.nlp-msg');
      var btn = form.querySelector('button');
    
      function say(text, ok) {
        msg.textContent = text;
        msg.className = 'nlp-msg ' + (ok ? 'ok' : 'bad');
        msg.hidden = false;
      }
    
      form.addEventListener('submit', function (e) {
        e.preventDefault();
        var email = form.email.value.trim();
        if (form.website.value) return;
        if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { say(form.dataset.bad, false); return; }
    
        var data = new URLSearchParams();
        data.append(form.dataset.field, email);
        btn.disabled = true;
        // Google Forms sends no readable answer to other sites (no-cors), so a
        // request that reaches Google counts as saved; only network errors fail.
        fetch(form.dataset.action, { method: 'POST', mode: 'no-cors', body: data })
          .then(function () { say(form.dataset.ok, true); form.reset(); })
          .catch(function () { say(form.dataset.fail, false); })
          .then(function () { btn.disabled = false; });
      });
    })();
    </script>
    

    Edit the title, text, button and the three messages (data-ok, data-bad, data-fail) freely. Keep the class names that start with nlp-.

    The page includes a hidden trap field. Bots that fill every field are silently ignored.

    See your subscribers

    Every signup appears in the form's Responses tab. Click Link to Sheets to get them in a Google Sheet, with the date and time of each signup.

    Google Forms Responses tab showing one email
    New signups land in Responses.

    Send your newsletter

    • Small list: copy the emails from the sheet into Gmail's Bcc field, so subscribers don't see each other.
    • Growing list: download the sheet as CSV and import it into an email service when you're ready.
    • Always add a line on how to unsubscribe, and remove people who ask.

    Questions

    Why does the page say "Thanks" even for a repeated email?

    Google Forms doesn't send an answer back to other sites, so the page can't know if the email is already in the list. Repeats show up as extra rows; remove them in the sheet.

    Does the reader leave my blog?

    No. The email is sent in the background and the thank-you shows inside the card.

    Does it slow down my blog?

    No. The code runs only on the newsletter page and contacts Google only when someone clicks Subscribe.

    Can I put the form somewhere else, like the footer?

    Yes. The same code works in an HTML gadget in Layout. Use it once per page.

    Is this allowed by Google?

    Yes. You are sending answers to your own public form, exactly as if the reader filled it in on Google's site.