DEV Community

Cover image for Go Contact Email API: Streamlined Contact Form with Send Email & MongoDB
Francisco Inoque
Francisco Inoque

Posted on

Go Contact Email API: Streamlined Contact Form with Send Email & MongoDB

Building a Go API to Collect and Respond to Contact Messages

In this article, we'll walk through building a simple Go API that receives contact information from users, stores it in a MongoDB database, and sends a confirmation email. This API can be used as a contact form on your website to collect messages from visitors.

Setting Up the Environment

First, let's set up our Go environment. We'll use the following packages:

  • github.com/joho/godotenv for loading environment variables from a .env file.
  • go.mongodb.org/mongo-driver/mongo for MongoDB database interactions.
  • gopkg.in/gomail.v2 for sending confirmation emails.
// Import required packages
import (
    "context"
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os"
    "strconv"

    "github.com/joho/godotenv"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
    "gopkg.in/gomail.v2"
)

// Define structs for data representation
type Contact struct {
    FirstName string `json:"firstName"`
    LastName  string `json:"lastName"`
    Email     string `json:"email"`
    Linkedin  string `json:"linkedin"`
    Tech      string `json:"tech"`
    Message   string `json:"message"`
}

type Response struct {
    Message string `json:"message"`
}

// Set up the MongoDB client
var client *mongo.Client

func main() {
    // Load environment variables from .env file
    err := godotenv.Load()
    if err != nil {
        log.Fatal("Error loading environment variables from .env file:", err)
    }

    // Establish a connection to MongoDB
    mongoDBURI := os.Getenv("MONGODB_URI")
    clientOptions := options.Client().ApplyURI(mongoDBURI)
    client, err = mongo.Connect(context.TODO(), clientOptions)
    if err != nil {
        log.Fatal(err)
    }

    // Ping MongoDB to confirm the connection
    err = client.Ping(context.TODO(), nil)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Connected to MongoDB")

    // Set up HTTP routes and start the server
    r := http.NewServeMux()
    r.HandleFunc("/api/contact", handleContact)

    http.Handle("/", r)

    // Get the port from environment variables or use a default port
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    fmt.Println("API started on port :" + port)
    log.Fatal(http.ListenAndServe(":"+port, nil))
}

// Handle contact form submissions
func handleContact(w http.ResponseWriter, r *http.Request) {
    // Decode the JSON data from the request
    var contact Contact
    err := json.NewDecoder(r.Body).Decode(&contact)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        log.Println("Error decoding JSON:", err)
        return
    }

    // Get the MongoDB collection to store contact data
    collection := client.Database("franciscoinoque-tech").Collection("contacts")

    // Insert data into MongoDB
    _, err = collection.InsertOne(context.TODO(), contact)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        log.Println("Error inserting data into MongoDB:", err)
        return
    }
    log.Println("Data inserted into MongoDB successfully")

    // Send a confirmation email
    err = sendEmail(contact)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        log.Println("Error sending email:", err)
        return
    }
    log.Println("Email successfully sent")

    // Send a JSON response
    response := Response{Message: "Data saved successfully and email sent!"}
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(response)
}

// Send a confirmation email
func sendEmail(contact Contact) error {
    // Load environment variables from .env file
    err := godotenv.Load()
    if err != nil {
        log.Fatal("Error loading environment variables from .env file")
        return err
    }

    // Get SMTP server settings from .env file
    smtpHost := os.Getenv("SMTP_HOST")
    smtpPortStr := os.Getenv("SMTP_PORT") // Read as string
    smtpUsername := os.Getenv("SMTP_USERNAME")
    smtpPassword := os.Getenv("SMTP_PASSWORD")

    // Convert port string to int
    smtpPort, err := strconv.Atoi(smtpPortStr)
    if err != nil {
        log.Fatal("Error converting SMTP port to int:", err)
        return err
    }

    // Configure the email client
    m := gomail.NewMessage()
    m.SetHeader("From", smtpUsername) // Use the sender's email address
    m.SetHeader("To", contact.Email)  // Recipient's email address
    m.SetHeader("Subject", "I've Received Your Message!")

    // Message body
    body := fmt.Sprintf("Hi,\n\n" +
    "I just wanted to let you know that I've received your message. I'm glad you reached out.\n\n" +
    "I'm taking a look at your message, and I'll get back to you shortly. I love receiving messages and I'm excited to chat more.\n\n" +
    "If you need anything or want to discuss further, feel free to shoot me an email directly at " + smtpUsername + ".\n\n" +


    "Thanks for choosing to write to me. I can't wait to continue our conversation.\n\n" +
    "Cheers,\n\n" +
    "Francisco Inqoue")
    m.SetBody("text/plain", body)

    // Configure the SMTP client with .env variables
    d := gomail.NewDialer(smtpHost, smtpPort, smtpUsername, smtpPassword)

    // Send the email
    if err := d.DialAndSend(m); err != nil {
        log.Println("Error sending email:", err)
        return err
    }

    log.Println("Email successfully sent")
    return nil
}
Enter fullscreen mode Exit fullscreen mode

Certainly! Here's an explanation of each function in your Go application in English:

  1. main():

    • This function is the entry point of the program.
    • Loads environment variables from the .env file using the github.com/joho/godotenv package.
    • Establishes a connection to MongoDB using the MongoDB URI information obtained from environment variables.
    • Initializes the HTTP router and defines a route to handle POST requests at "/api/contact."
    • Starts the HTTP server on the port specified in the environment variables (or the default port 8080).
  2. handleContact(w http.ResponseWriter, r *http.Request):

    • This function handles POST requests at "/api/contact."
    • Decodes JSON data from the HTTP request into a Contact struct.
    • Retrieves a collection in MongoDB to store contact data.
    • Inserts contact data into MongoDB.
    • Calls the sendEmail() function to send a confirmation email.
    • Returns a JSON response indicating that the data has been saved successfully.
  3. sendEmail(contact Contact) error:

    • This function sends a confirmation email after receiving contact information.
    • Loads environment variables from the .env file to obtain SMTP server settings.
    • Configures an SMTP client using the provided information.
    • Creates an email message with a formatted body.
    • Sends the confirmation email using the configured SMTP client.

Each function plays a crucial role in the operation of your application. main() is the entry point that starts the server, handleContact() handles contact requests and database insertion, while sendEmail() takes care of sending the confirmation email. Together, these functions allow your application to receive contact messages, store them in MongoDB, and send a confirmation email to the senders.
This article provides a step-by-step guide on how to build a Go API that collects contact messages from users and sends a confirmation email. You can adapt this API for your own projects or website to enhance user interaction and engagement. Happy coding!

Star this repository
Francisco Inoque

Top comments (0)