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



This content originally appeared on HackerNoon and was authored by Karol Horosin

\

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("<https://api.sendfox.com/contacts>", {
    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 = () => (
  <Button disabled>
    <Loader2 className="mr-2 h-4 w-4 animate-spin" />
    Please wait
  </Button>
);

const SendFoxForm = () => {
  const [email, setEmail] = useState("");
  const [status, setStatus] = useState<FormStatus>("idle");
  const [errorMessage, setErrorMessage] = useState("");

  const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    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 (
    <div className="w-full">
      <form
        onSubmit={handleSubmit}
        className="flex w-full max-w-md items-center space-x-2 mx-auto"
      >
        <Input
          className="w-full"
          type="email"
          placeholder="Email"
          name="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          required
          disabled={status === "loading" || status === "success"}
        />
        {status === "loading" ? (
          <ButtonLoading />
        ) : (
          <Button type="submit" disabled={status === "success"}>
            {status === "success" ? "Subscribed!" : "Subscribe"}
          </Button>
        )}
      </form>
      <div className="pt-2 min-h-[1em]">
        {(status === "idle" || status === "loading") && <p>&nbsp;</p>}
        {status === "error" && (
          <p className="text-sm text-red-500 text-center">{errorMessage}</p>
        )}
        {status === "success" && (
          <p className="text-sm text-muted text-center">
            Subscription successful! Thank you for joining.
          </p>
        )}
      </div>
    </div>
  );
};

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: idleloading, 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!


This content originally appeared on HackerNoon and was authored by Karol Horosin