상세 컨텐츠

본문 제목

[Go] Go Fiber / SMTP / Google Email 전송 API

golang

by 거니 노트 2023. 7. 27. 11:51

본문

이메일 전송하는 상황이 많을거 같아서 미리 만들어 두기로 했다.

SMTP를 사용하여 구글 이메일을 보내는 API를 만들어 보았다.

 

Github

https://github.com/kimguny/send-email

 

웹 프레임워크

go fiber

 

go packages

net/smtp

 

1. app 계정 생성

보안 정책이 바뀌면서 app 계정을 생성해줘야 한다.

 

구글 설정 -> 보안 -> 2단계 인증 -> 앱 비밀번호

앱 비밀번호를 생성한 뒤 나오는 비밀번호를 따로 저장해 둔다.

2. go 환경변수 설정

go 프로젝트를 생성한 뒤 .env 파일을 생성해준다.

 

.env.example

SMTP_USERNAME=""
SMTP_PASSWORD=""

SMTP_FROM=""

깃허브에 올릴때는 보안 때문에 .env 파일은 gitignore로 커밋하지 않고 .env.example을 커밋한다.

패스워드에 아까 저장해둔 앱 비밀번호를 넣으면 된다.

 

3. API 요청

Key Value
Method POST
URL /send_email

Request Body

Key Value
to [string]

CURL

curl --location 'http://127.0.0.1:8080/send_email' \
--header 'Content-Type: application/json' \
--data-raw '{
    "to": "{전송 할 이메일}"
}'

main.go 생성 후 아래와 같이 코드를 작성했다.

package main

import (
	"bytes"
	"fmt"
	"log"
	"mime/multipart"
	"net/smtp"
	"os"

	"github.com/gofiber/fiber/v2"
	"github.com/joho/godotenv"
)

type ResponseData struct {
	To string `json:"to"`
}

func main() {
	// .env 읽기
	err := godotenv.Load()
	if err != nil {
		fmt.Println(err)
		return
	}

	app := fiber.New()

	app.Post("/send_email", send_email)

	log.Fatal(app.Listen(":8080"))
}

func send_email(c *fiber.Ctx) (err error) {
	// 환경변수
	smtpUsername := os.Getenv("SMTP_USERNAME")
	smtpPassword := os.Getenv("SMTP_PASSWORD")
	smtpFROM := os.Getenv("SMTP_FROM")

	// POST 요청 body 파싱
	var responseData ResponseData

	err = c.BodyParser(&responseData)
	if err != nil {
		fmt.Println(err)
		return err
	}

	// SMTP 인증 정보 설정
	smtpHost := "smtp.gmail.com"
	smtpPort := 587
	auth := smtp.PlainAuth("", smtpUsername, smtpPassword, smtpHost)

	// 메시지 작성
	headerSubject := "메일 테스트\r\n"
	headerBlank := "\r\n"
	body := "메일 테스트 입니다.\r\n"
	msg := []byte(headerSubject + headerBlank + body)

	// MIME 멀티파트 바디 생성
	buf := new(bytes.Buffer)
	writer := multipart.NewWriter(buf)

	// 텍스트 파트 추가
	textPart, err := writer.CreatePart(map[string][]string{
		"Content-Type": {"text/plain; charset=UTF-8"},
	})
	if err != nil {
		fmt.Println(err)
		return err
	}
	textPart.Write(msg)

	// 메일 헤더 설정
	header := make(map[string]string)
	header["From"] = smtpFROM
	header["To"] = responseData.To
	header["Subject"] = "메일 테스트"
	header["MIME-Version"] = "1.0"
	header["Content-Type"] = writer.FormDataContentType()

	// 메일 보내기
	err = smtp.SendMail(fmt.Sprintf("%s:%d", smtpHost, smtpPort), auth, smtpFROM, []string{responseData.To}, composeEmail(header, buf.Bytes()))
	if err != nil {
		fmt.Println(err)
		return err
	}

	return c.SendStatus(200)
}

func composeEmail(header map[string]string, body []byte) []byte {
	var email bytes.Buffer

	for key, value := range header {
		email.WriteString(fmt.Sprintf("%s: %s\r\n", key, value))
	}

	email.WriteString("\r\n")
	email.Write(body)

	return email.Bytes()
}

요청을 보내면 이메일이 전송된다.

관련글 더보기