#6 Golang gomail을 이용해 SMTP 연동하기

2020. 1. 27. 19:17 개발 이야기/Golang

 

안녕하세요.

 

실직으로 인해 정말 오랫만에 블로그에 글을 쓰는 것 같습니다..

 

심리적으로 정말 힘든 요즘이네요 ㅎㅎ

 

그래도! 멈출수는 없으니까~~ ㅎㅎ

 

 

오늘은 구현해 놓은지는 조금된 기능인데요

 

SMTP 연동입니다.

 

SMTP는 


simple mail transfer protocol의 약어. 인터넷 상에서 전자 메일을 전송할 때 쓰이는 표준적인 프로토콜. SMTP 프로토콜에 의해 전자 메일을 발신하는 서버(server)를 SMTP 서버라고 한다. 메일 사이에서 발생하는 것을 전송해 주는 프로토콜로 인터넷에서 이메일을 교환할 때 그 과정을 정렬해준다.

[네이버 지식백과] SMTP [simple mail transfer protocol] (컴퓨터인터넷IT용어대사전, 2011. 1. 20., 전산용어사전편찬위원회)


 

메일 전송을 할 때 사용하는 프로토콜인데요

 

SMTP 서버를 구축하고 자체 SMTP를 사용할 수도 있고

 

naver나 google의 SMTP 서버를 사용할 수도 있도록

 

코드를 작성해보도록 하겠습니다.

 

 

모듈은 gomail을 사용해보겠습니다.

 

먼저 SMTP 정보를 저장할 수 있는 DB 스키마를 작성하고

 

사용자마다 사용하고 싶은 SMTP 서버 정보를 넣는 input form을 만들어서 구현을 했습니다.

 

 

이렇게 SMTP 서버 정보를 입력해 놓으면

 

정상적으로 연결이 되는지 연결 테스트를 하고 저장하도록 프로세스를 만들었는데요

 

자 그럼 연결테스트를 누르면 이 정보를 가지고 연결이 정상적으로 되는지 확인 하는 로직을 구현해보겠습니다.

 

먼저 gomail을 사용하려면!

go get gopkg.in/gomail.v2

 

 

SMTP 정보를 담을 수 있는 구조체를 만들어 줍니다.

type Smtpinfo struct {
    SmtpNo       int    `json:"smtp_no"`
    SmtpHost     string `json:"smtp_host"`
    SmtpPort     string `json:"smtp_port"`
    SmtpProtocol string `json:"smtp_protocol"`
    SmtpTls      string `json:"smtp_tls"`
    SmtpTimeout  string `json:"smtp_timeout"`
    SmtpId       string `json:"smtp_id"`
    SmtpPw       string `json:"smtp_pw"`
    SmtpIdentity string `json:"smtp_identity"`
}

 

 

그리고 front-end 에서 보낸 정보를 BIND해주겠습니다.

func SmtpConnectionCheck(c *gin.Context) {
    var si mail.Smtpinfo
    err := c.BindJSON(&si)
    err = si.IdPwCheck()
    err = si.SmtpConnectionCheck(model.GetUserNo(c))
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "status": http.StatusBadRequest,
            "isOK":   0,
            "error":  err,
        })
        return
    }
    c.JSON(http.StatusOK, gin.H{
        "status":       http.StatusOK,
        "isOK":         1,
    })
}

 

바인딩을 해준 후 SmtpConnectionCheck 메서드를 이용해 Smtp 정보가 연결 가능한 정보인지 확인을 하는데요!

gomail.NewDialer 메서드로 다이얼을 만들어주고

Dial 메서드를 실행해 err가 있으면 연결에 실패한 것으로

판단할 수있습니다. 디버깅을 해보겠습니다.

func (si *Smtpinfo) SmtpConnectionCheck(userNo int) error {
    port, _ := strconv.Atoi(si.SmtpPort)
    d := gomail.NewDialer(si.SmtpHost, port, si.SmtpId, si.SmtpPw)
    // d.Dial()
    _, err := d.Dial()

    if err != nil {
        return err
    }
    return nil
}

 

 

잘못된 정보를 입력했을 때

not accepted 에러가 발생할 것을 확인할 수 있죠?

 

정상적인 정보를 입력하면?

에러가 nil인 것을 확인할 수있습니다.

 

자 이렇게 연결 테스트 로직을 구현했으면

 

메일을 보내봐야겠죠?

테스트로 메일을 보낼 수 있는 api를 만들었습니다.

func SendMailTest(c *gin.Context) {
    var si mail.Smtpinfo
    err := c.BindJSON(&si)
    err = si.SendMail()
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "status": http.StatusBadRequest,
            "isOK":   0,
            "error":  err.Error(),
        })
        return
    }
    c.JSON(http.StatusOK, gin.H{
        "status": http.StatusOK,
        "isOK":   1,
    })

}

 

smtp 연결 테스트와 유사하게 로직을 구현했구요

 

간단히 bind 후 sendMail 메서드 실행 입니다.

 

gomail을 이용한 메일 전송 로직은 그냥 smtp 모듈을 사용하는 것과 거의 같다고 생각이 들었는데요

 

func (si *Smtpinfo) SendMail() error {

    // var list []struct {
    //     Name    string
    //     Address string
    // }

    port, _ := strconv.Atoi(si.SmtpPort)

    d := gomail.NewDialer(si.SmtpHost, port, si.SmtpId, si.SmtpPw)
    s, err := d.Dial()
    if err != nil {
        return err
    }

    m := gomail.NewMessage()
    // for _, r := range list {
    m.SetHeader("From", "보내는계정@naver.com")
    m.SetAddressHeader("To", "받는계정@gmail.com", "Minseok")
    m.SetHeader("Subject", "Newsletter #1")
    m.SetBody("text/html", fmt.Sprintf("Hello %s!", "Minseok"))

    if err := gomail.Send(s, m); err != nil {
        return fmt.Errorf(
            "Could not send email to %q: %v", "보내는계정@naver.com", err)
    }
    m.Reset()
    // }
    return nil

}

간단히 전송만 하도록 구현했는데요

 

smtp check 로직과 동일하게 먼저 dial을 확인해 연결이 가능한지 확인을 한 후

 

NewMessage 작성해줍니다.

 

여기서 혼돈할 수 있는 부분은

 

보내는 계정이 smtp에 연동된 계정과 다르다면 아래와 같은 에러가 발생하게됩니다.

 

 

정상적으로 계정을 입력해서 보내게되면

 

 

정상적으로 메일이 보내진 것을 확인할 수있습니다.

 

이렇게 SMTP 를 golang에서도 사용할 수있는데요!

 

메일을 이용해 개인정보 처리방침 등의 변경이 있는 경우

 

공지를 해주면 아주 좋겠죠?

 

이상입니다