How to Create a Newsletter using Contibase and SvelteKit-UI

Published:

10 minute view time

How to Create a Newsletter using Contibase and SvelteKit-UI

YouTube Version of this Post

Set Up Your Coding Environment

First, we'll get your custom website started. If you are newer to web development you should get your basic coding environment set up. You can use your own set up, but I keep it pretty simple:

  • Apple Macbook Pro laptop
  • Visual Studio Code (VS Code)

    Link Preview

    Visual Studio Code (VS Code)

    https://code.visualstudio.com/

    desktop app for the code editor
  • Github Desktop

    Link Preview

    Github Desktop

    https://desktop.github.com/download/

    to access and save projects to Github, which is industry standard and what will connect to your web host (likely Vercel) later to publish site.

Initialize Project Code for Website

In your file finder create a folder to use for your project. I like to use a folder name ending in -all like "sharktankupdate-all" and then you can place all things related to your project in that folder including your code.

Right click on a folder in "Finder" and click "Copy relative path" and then in your terminal type cd, paste the path, and hit enter. It might look something like

cd /Users/someuser/Documents/projects/my-project-all
.

Now, we'll start your project code from a template using sveltekit-ui

Link Preview

sveltekit-ui

https://www.sveltekit-ui.com/

. In your terminal run (but replace "my-project" with your own project name like "shark-tank-update"):
npx create-sveltekit-ui-site my-project

Navigate into your project folder:

cd my-project
. The starter template should be close to up-to-date but you can run
ncu -u
to update the npm packages to the latest versions. Then install them with
npm i
. Open your code editor such as VS Code. You should be able to type
code .
in your terminal to open your project code.

To run the project locally run

npm run dev
and open up your browser to
http://localhost:5173/
.

Contibase and Sveltekit-UI coding setup

Good Progress! Let's Keep Going

You can play around with your front end website a bit if you want and get a first look at helpful resources like sveltekit-ui.com

Link Preview

sveltekit-ui.com

https://www.sveltekit-ui.com

and Svelte Docs

Link Preview

Svelte Docs

https://svelte.dev/docs/kit/introduction

. You can do more custom development later, though. Let's finish configuring the project to connect to your Contibase backend.

The starter template includes a setup to collect user email addresses in a newsletter subscribe form, which adds a user to your users table in contibase.com/tables. We will setup sending a verification email to users when they are added to the users table. The verification email will include a link to a page on your website that we will use to confirm that user on link click.

Connect to Contibase

Switch over to contibase.com

Link Preview

contibase.com

https://www.contibase.com

. Create an account if you haven't already.

Connect Domain and Create Custom Email Addresses

Go to contibase.com/settings/domains and follow the steps to confirm your ownership of a domain. If you don't yet have a domain try and buy one on Vercel

Link Preview

Vercel

https://www.vercel.com

.

Follow the process of adding DNS records to your domain to provide Contibase access to send and receive emails from your domain. You should also add a subdomain and dns records for that because its best practice to send emails from a subdomain such as mail.mydomain.com to protect the reputation of your root domain.

Then, create an email address from that subdomain that we will use to send mail from such as newsletter@mail.mydomain.com.

Contibase custom domain and email address setup

Build Email Verification Page Template

Go to contibase.com/pages, and create a new page to serve as an email template to send to users an email verification link after they are added as a user.

On the page edit screen, you can edit the page as you wish, but for now we made a basic template to get you started. Copy the json snippet below. Then, in the Contibase page edit screen click on "settings" and paste the json into the text input and click "Set Changes".

json

{
  "id": null,
  "account_id": null,
  "full_path": ["mail", "user_email_address_verification"],
  "account_page_full_path": null,
  "main_image": null,
  "main_audio": null,
  "main_video": null,
  "title": {
    "type_id": "base_text",
    "children": [],
    "attributes": { "content": "Verify Your Subscription", "text_color": null },
    "selector_id": "innmyiei"
  },
  "description": {
    "type_id": "base_text",
    "children": [],
    "attributes": {
      "content": "Confirm your subscription to receive the latest updates delivered straight to your inbox.",
      "text_color": null
    },
    "selector_id": "tjakiyge"
  },
  "email_subject": {
    "type_id": "base_text",
    "children": [],
    "attributes": { "content": "Confirm your email address", "text_color": null },
    "selector_id": "uqsdmkxe"
  },
  "email_content_preview": {
    "type_id": "base_text",
    "children": [],
    "attributes": { "content": "Click to confirm email address", "text_color": null },
    "selector_id": "bhijvjcs"
  },
  "attachments": null,
  "keywords": null,
  "location_relevant": null,
  "time_relevant": null,
  "time_created": null,
  "time_updated": null,
  "is_template": false,
  "is_open_in_external_url_button": false,
  "is_open_in_browser_button": false,
  "is_show_header_in_content": false,
  "is_feedback_component": false,
  "segments": {
    "main": {
      "val": {
        "type_id": "div",
        "children": [
          {
            "type_id": "h2",
            "children": [
              {
                "type_id": "base_text",
                "children": [],
                "attributes": { "content": "Almost There! Confirm Your Email", "text_color": null },
                "selector_id": "swowxhsn"
              }
            ],
            "attributes": {},
            "selector_id": "pbvghfxz"
          },
          {
            "type_id": "p",
            "children": [
              {
                "type_id": "base_text",
                "children": [],
                "attributes": { "content": "Thanks for joining!", "text_color": null },
                "selector_id": "dozfungd"
              }
            ],
            "attributes": {},
            "selector_id": "ktjjpftg"
          },
          {
            "type_id": "p",
            "children": [
              {
                "type_id": "base_text",
                "children": [],
                "attributes": { "content": "Click the button below to confirm your subscription:", "text_color": null },
                "selector_id": "agloxrpc"
              }
            ],
            "attributes": {},
            "selector_id": "jitqfwis"
          },
          {
            "type_id": "link",
            "children": [
              {
                "type_id": "base_text",
                "children": [],
                "attributes": { "content": "Confirm My Subscription", "text_color": null },
                "selector_id": "ckbtdcwu"
              }
            ],
            "attributes": {
              "text_color": null,
              "display_text": null,
              "is_show_preview": null,
              "href_from_variable_path": ["variables", "email_message_variables", "confirm_email_address_url"]
            },
            "selector_id": "cdvfjbwh"
          },
          {
            "type_id": "p",
            "children": [
              {
                "type_id": "base_text",
                "children": [],
                "attributes": { "content": "Or copy the following link into your browser", "text_color": null },
                "selector_id": "phkvwiai"
              }
            ],
            "attributes": {},
            "selector_id": "jwpbgwgv"
          },
          {
            "type_id": "p",
            "children": [
              {
                "type_id": "base_text",
                "children": [],
                "attributes": {
                  "text_color": null,
                  "content_from_variable_path": ["variables", "email_message_variables", "confirm_email_address_url"]
                },
                "selector_id": "rjsticoq"
              }
            ],
            "attributes": {},
            "selector_id": "ntmpzmky"
          },
          {
            "type_id": "p",
            "children": [
              {
                "type_id": "base_text",
                "children": [],
                "attributes": {
                  "content": "If you didn't sign up for this, just ignore this email.",
                  "text_color": null
                },
                "selector_id": "zrussnec"
              }
            ],
            "attributes": {},
            "selector_id": "xilibncs"
          },
          {
            "type_id": "p",
            "children": [
              {
                "type_id": "base_text",
                "children": [],
                "attributes": { "content": "Welcome aboard!", "text_color": null },
                "selector_id": "awhezmzj"
              },
              { "type_id": "br", "children": [], "attributes": {}, "selector_id": "qbfypjtl" },
              {
                "type_id": "base_text",
                "children": [],
                "attributes": { "content": "The Team", "text_color": null },
                "selector_id": "exyzjarj"
              }
            ],
            "attributes": {},
            "selector_id": "ldgcuxgq"
          }
        ],
        "attributes": {
          "padding": 1,
          "border_color": { "c": 10, "h": 18, "l": 0, "o": 24, "is_dark_theme_invert": true },
          "align_content": null,
          "border_radius": 1,
          "justify_content": null,
          "background_color": null
        },
        "selector_id": "cdrhxena"
      },
      "display_order": 0,
      "is_for_editors_only": false
    },
    "helper": { "val": null, "display_order": 1, "is_for_editors_only": true }
  },
  "metadata": null,
  "external_url": null,
  "note": null,
  "epoch_listed_on_contibase": null,
  "epoch_indexable_by_search_engines": null,
  "db_epoch_created": null,
  "db_epoch_updated": null,
  "page_variables": null,
  "email_message_variables": null
}

We send the user a url specific to that user, so when that user clicks the link to confirm, you will update the user when that url path is visited. You can customize this email to suit your brand etc. But probably keep this email minimal to keep the focus on verifying email and also not add too many third party links or images that could increase the chance of the email landing in junk.

The url will be passed in as a variable called "confirm_email_address_url" when we send the email. In the template we reference that variable with ["variables", "email_message_variables", "confirm_email_address_url"]

Email verification Contibase page edit screen

Create a Function to Automate Sending Verification Emails 🚀

Use Contibase Functions and Triggers to send emails when a new user row is created. Let's make that function. Go to contibase.com/functions and create a function. You can name it "User Email Address Verification"

Copy the function template below and use it in the "Paste Function Structure" area on the function edit page.

json

{
  "type": "function_literal",
  "value": {
    "do": {
      "type": "stack_literal",
      "value": [
        {
          "type": "define",
          "value": {
            "value": {
              "type": "arithmetic_binary_operation",
              "value": {
                "a": { "type": "text_literal", "value": "https://www.mydomain.com/confirm_user_email_address/" },
                "b": { "type": "variable_path_literal", "value": ["main_input", "row", "id"] },
                "operator": { "type": "text_literal", "value": "add" }
              }
            },
            "identifier": { "type": "identifier_literal", "value": "confirm_email_address_url" }
          }
        },
        {
          "type": "log",
          "value": {
            "type": { "type": "text_literal", "value": "basic" },
            "label": { "type": "text_literal", "value": "test" },
            "value": { "type": "defined_target_literal", "value": "confirm_email_address_url" }
          }
        },
        {
          "type": "send_email",
          "value": {
            "page_id": { "type": "text_literal", "value": "sywnodssswvowaxtuuzs" },
            "to_full": {
              "type": "array_expression",
              "value": [
                {
                  "type": "object_expression",
                  "value": [
                    {
                      "type": "object_expression_item",
                      "value": {
                        "key": { "type": "text_literal", "value": "email_address" },
                        "value": { "type": "variable_path_literal", "value": ["main_input", "row", "email_address"] }
                      }
                    }
                  ]
                }
              ]
            },
            "from_full": {
              "type": "text_literal",
              "value": { "email_address": "newsletter@mail.mydomain.com" }
            },
            "epoch_schedule_send": null,
            "email_message_variables": {
              "type": "object_expression",
              "value": [
                {
                  "type": "object_expression_item",
                  "value": {
                    "key": { "type": "text_literal", "value": "confirm_email_address_url" },
                    "value": {
                      "type": "get_defined",
                      "value": {
                        "defined_target": { "type": "defined_target_literal", "value": "confirm_email_address_url" }
                      }
                    }
                  }
                }
              ]
            }
          }
        },
        {
          "type": "return",
          "value": {
            "value": {
              "type": "get_defined",
              "value": { "defined_target": { "type": "defined_target_literal", "value": "confirm_email_address_url" } }
            }
          }
        }
      ]
    },
    "name": { "type": "text_literal", "value": "Main" },
    "input_identifier": { "type": "identifier_literal", "value": "main_input" }
  }
}
Email Verification Contibase function setup

Replace the placeholder data in this template with your own. Change "mydomain" to your custom domain. Change from email address to the custom email address you made. Change page id to the email verification page id we just made.

Go to contibase.com/tables and select your users table. Add a function trigger using "On Row Created" and select the "User Email Address Verification" function to trigger. Make sure "Is Enabled" is toggled on.

Add Contibase Variables to Project .env

Back in VS Code, go to the .env.example file and rename it .env then fill out your CONTIBASE_ACCESS_TOKEN. You can create one at contibase.com/settings/auth by clicking "Create Access Token".

Also, add CONTIBASE_USERS_TABLE_ID from finding your users table at contibase.com/tables. Lastly, set CONTIBASE_ACCOUNT_ID, which can be found in contibase.com/settings.

Do not share your CONTIBASE_ACCESS_TOKEN publically because it provides full access to your account. In SvelteKit files like +server.js and +page.server.js are where you can safely use it to make calls to the Contibase api from a protected server envirnment.

Successfully Setup (Locally)

Let's test if it works. Go to your running browser tab on localhost and in the newsletter add a name, email address, and submit.

This should send an email when you add a user to you users table. The link will still be to your custom domain. You can test a link click by going on your local machine with http://localhost:5173/confirm_user_email_address/[user_id_to_confirm]

Localhost running dev site

Save your Project code to Github

If you don't already have one, create a GitHub

Link Preview

GitHub

https://github.com

account to save your projects. In the Github Desktop app for your Macbook, add your project that we just made locally on your computer and push your changes to save them remotely.

Create a new branch called "dev" to use while you are making progress and when you are pleased with the work you can use a pull request to merge it into main. Main will be used in the live website when we set that up later.

Wrapping Up 🎉

You now have a working blog/newsletter using SvelteKit-UI and Contibase working locally. Next let's customizing your project, and publish your live site.

The live version of the code from this tutorial project can be found at Live Github Code

Link Preview

Live Github Code

https://github.com/upppllc/survivorsnuff

. It includes changes beyond this stage of the tutorial. You can continue with the next part of this tutorial to get the icons, website content, and push to live domain.

Continue following along in the next post, Customize Your Website

Link Preview

Customize Your Website

https://www.contibase.com/blog/customize-website

.

Authentication

Chat Assistant

Output Type:

No Chat History