Your resource for web content, online publishing
and the distribution of digital products.
S M T W T F S
 
 
 
 
 
1
 
2
 
3
 
4
 
5
 
6
 
7
 
8
 
9
 
10
 
11
 
12
 
13
 
14
 
15
 
16
 
17
 
18
 
19
 
20
 
21
 
22
 
23
 
24
 
25
 
26
 
27
 
28
 
29
 
30
 

Creating a SendFox Newsletter Signup Form in Next.js: A Tutorial

DATE POSTED:September 7, 2024

\

Introduction

SendFox is a popular newsletter service built by AppSumo. The company is famous for its store with lifetime deals for software. The product has limitations and is not a perfect solution, but if you need a solid tool with predictable cost, it may be just the fit for you. There's a generous free tier as well.

\ There aren't many examples online for how to create a signup form outside of embedding one. They don't look the best and don't play nice with JS frameworks.

\ Let's create a form component and an API route in Next.js that will give us full control.

\ I am using shadcn/ui for UI components and lucide-react for icons. You can easily swap these components for something else.

Set-Up

Skip if you're adding this to an existing app.

\ If you want to follow this tutorial from scratch, perform the following steps.

\

  1. Set up Next.js app with shadcn/ui - link

    \

  2. Add components: npx shadcn-ui@latest add button input

    \

  3. Install icons pack: npm i lucide-react

    \

You're good to go.

\

SendFox API

SendFox has a very basic API documentation, which you can find here: https://help.sendfox.com/article/278-endpoints.

\ You will need to get an API key from your SendFox account. Go to the settings, API section, and click "Create new token."

\ Copy and store safely.

API Route

Let's start with an API route that will handle our sign-up logic.

\ You can add more verification to this code to pre-filter spammy sign-ups.

\ You may want to also save emails somewhere other than SendFox for redundancy.

\ I've created a file app/api/newsletter/route.ts with the following content:

\

export async function POST(request: Request) { const { email } = await request.json(); if (!email) { return Response.json({ error: "Email is required" }, { status: 400 }); } const response = await fetch("", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.SENDFOX_TOKEN}`, }, body: JSON.stringify({ email, }), }); if (!response.ok) { return Response.json({ error: "Failed to subscribe" }, { status: 500 }); } return Response.json({ message: "Subscribed successfully" }); }

\ You can test it in Postman or via curl or just jump in to create a form.

Form Component

Create a file app/components/send-fox-form.tsx with the following content:

\

"use client"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Loader2 } from "lucide-react"; import { useState } from "react"; type FormStatus = "idle" | "loading" | "success" | "error"; const ButtonLoading = () => ( ); const SendFoxForm = () => { const [email, setEmail] = useState(""); const [status, setStatus] = useState("idle"); const [errorMessage, setErrorMessage] = useState(""); const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); setStatus("loading"); setErrorMessage(""); try { const response = await fetch("/api/newsletter", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ email: email.trim().toLowerCase() }), }); const data = await response.json(); if (response.ok) { setStatus("success"); } else { setStatus("error"); setErrorMessage(data.message || "Failed to subscribe"); } } catch (error) { setStatus("error"); setErrorMessage("An error occurred while trying to subscribe."); } }; return (
setEmail(e.target.value)} required disabled={status === "loading" || status === "success"} /> {status === "loading" ? ( ) : ( )}
{(status === "idle" || status === "loading") &&

 

} {status === "error" && (

{errorMessage}

)} {status === "success" && (

Subscription successful! Thank you for joining.

)}
); }; export default SendFoxForm;

\ The SendFoxForm component handles the subscription logic and user interaction. It utilizes useState to manage the form's status and user input. The form includes three states: idle, loading, and success, each guiding the user through the subscription process with appropriate feedback.

\ Business Logic Overview:

\

  1. Form Submission Handling:
  • When the form is submitted, it prevents the default form behavior and sets the status to loading.

  • The email input is trimmed and converted to lowercase before being sent to the server.

    \

  1. API Interaction:
  • The form makes a POST request to the /api/newsletter route with the user's email.

  • If the response is successful (response.ok), the status changes to success.

  • If there's an error, the status changes to error, and an appropriate error message is displayed.

    \

  1. User Feedback:
  • While the form is submitting, a loading button is displayed to inform the user to wait.

  • If the subscription is successful, a "Subscribed!" message is shown, and further input is disabled.

  • If there is an error, an error message is displayed, guiding the user to rectify the issue.

    \

Conclusion

You now have a working SendFox newsletter sign-up form in your Next.js app.

\ While SendFox is in no way perfect, it may be the right choice for your first newsletter or a side project.

\ Personally, I used it for one of my upcoming projects and it's been a good experience so far. It lacks features related to managing multiple lists of contacts, so it may not be the best choice if you're running a few projects with separate domains.

\ Subscribe to my profile by filling in your email address on the left, and be up-to-date with my articles! I will soon be releasing a crazy interesting project that uses this solution!

\ Don't forget to follow me on Twitter @horosin, and subscribe to my blog’s newsletter for more tips and insights!