package routes
import (
"bytes"
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"mime"
"mime/multipart"
"mime/quotedprintable"
"net/http"
"net/mail"
"strconv"
"strings"
"github.com/taknb2nch/go-pop3"
)
type popMail struct {
Title string
From string
To string
Uid string
Date string
Content string
}
func pop(w http.ResponseWriter, r *http.Request) {
addr := "pop.naver.com:995"
client, err := pop3.Dial(addr) //pop3.go의 net.Dial -> tls.Dial (,nil)
if err != nil {
log.Printf("Error1: %v\n", err)
}
defer func() {
client.Quit()
}()
if err = client.User("in3166@naver.com"); err != nil {
log.Printf("Error2: %v\n", err)
return
}
if err = client.Pass("dlsgh12"); err != nil {
log.Printf("Error: %v\n", err)
return
}
var count int
var size uint64
if count, size, err = client.Stat(); err != nil {
log.Printf("Error: %v\n", err)
return
}
log.Printf("Count: %d, Size: %d\n", count, size)
var content string
var data1 []popMail
for i := count; i > 180; i-- {
if number, uid, err := client.Uidl(i); err != nil {
log.Printf("Uidl Error: %v\n", err)
return
} else {
log.Printf("i: %d, Number: %d, Uid: %s\n \n", i, number, uid)
if content, err = client.Retr(i); err != nil {
log.Printf("Error: %v\n", err)
return
} else {
msg, err := mail.ReadMessage(bytes.NewBufferString(content))
if err != nil {
log.Fatal("Cannot parse myMessage.")
}
fmt.Println("\n--------2body--------------")
date1, _ := msg.Header.Date()
fmt.Println("1DATE: ", date1.Format("2006-01-02 15:04:05"))
fmt.Println("1To: ", msg.Header.Get("To"))
fmt.Println("1From: ", decodeRFC2047(msg.Header.Get("From")))
fmt.Println("1Subject: ", decodeRFC2047(msg.Header.Get("Subject")))
fmt.Println("msg.Header.Get(Content-Type): ", msg.Header.Get("Content-Type"))
fmt.Println("msg.Header.Get(Content-Transfer-encoding): ", msg.Header.Get("Content-Transfer-encoding"))
//multipart
ss := multipartFunc(w, content)
if err != nil {
log.Fatal(err)
}
//fmt.Println(ss)
fmt.Println("\n--------2end--------------")
data := popMail{
Title: decodeRFC2047(msg.Header.Get("Subject")),
From: decodeRFC2047(msg.Header.Get("From")),
To: msg.Header.Get("To"),
Date: date1.Format("2006-01-02 15:04:05"),
Uid: uid,
Content: ss,
}
data1 = append(data1, popMail{
Title: decodeRFC2047(msg.Header.Get("Subject")),
From: decodeRFC2047(msg.Header.Get("From")),
To: msg.Header.Get("To"),
Date: date1.Format("2006-01-02 15:04:05"),
Uid: uid,
Content: ss,
})
fmt.Println(i, ": --Last-- data")
//fmt.Println(data)
file, _ := json.MarshalIndent(data, "", " ")
t := strconv.Itoa(i)
var url string = "public/mailboxes/in3166@naver.com/inbox/" + string(t) + ".json"
err1 := ioutil.WriteFile(url, file, 0777)
if err1 != nil {
log.Println("저장 오류", err1)
}
}
}
}
if err = client.Noop(); err != nil {
log.Printf("Error: %v\n", err)
return
}
if err = client.Rset(); err != nil {
log.Printf("Error: %v\n", err)
return
}
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(200)
b, err := json.MarshalIndent(data1, "", " ")
if err != nil {
panic(err)
}
w.Write(b)
}
func multipartFunc(w http.ResponseWriter, content string) string {
log.Println("1")
strings.ReplaceAll(content, "\n", "\r\n")
msg, err := mail.ReadMessage(bytes.NewBufferString(content))
if err != nil {
log.Println("1 error: ", err)
return ""
}
fmt.Println("$$$ msg.Header.Get(Content-Type): ", msg.Header.Get("Content-Type"))
var uDec []byte // 본문
mediaType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type"))
fmt.Println("$$$$$ params boundary: ", params["boundary"])
fmt.Println("$$$$$ mediaType: ", mediaType)
if err != nil {
log.Fatal("2 error: ", err)
}
if strings.HasPrefix(mediaType, "multipart/") {
mr := multipart.NewReader(msg.Body, params["boundary"])
i := 1
for {
fmt.Println(i, ": !!!!!!!!!!!!!!!!!!")
i++
p, err := mr.NextPart()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Println("$$$$$ p.Header.Get(Content-Type): ", p.Header.Get("Content-Type"))
slurp, err := ioutil.ReadAll(p) //본문
if err != nil {
log.Fatal(err)
}
encoding := p.Header.Get("Content-Transfer-Encoding\n")
if encoding == "" {
encoding = "7bit"
}
if strings.Contains(p.Header.Get("Content-Type"), "multipart") {
newContent := "Mime-Version: 1.0\n" + "Message-ID: " + randomString(12) + "\nContent-Type: " + p.Header.Get("Content-Type") + "\nContent-Transfer-Encoding: " + encoding + ";\n\n" + string(slurp) // 헤더와 본문 사이의 띄움
ss := multipartFunc(w, newContent)
log.Println("현재 컨텐츠: ", ss)
return ss
}
if !(strings.Contains(strings.ToUpper(p.Header.Get("Content-Type")), "UTF-8") || strings.Contains(strings.ToUpper(p.Header.Get("Content-Type")), "EUC-KR") || strings.Contains(strings.ToUpper(p.Header.Get("Content-Type")), "US")) {
fmt.Println("break: ", p.Header.Get("Content-Type"))
break
}
//fmt.Println("사전 검사 본문: ", string(slurp))
//fmt.Println("사전 검사 Encoding: ", p.Header.Get("Content-Transfer-Encoding"))
if strings.Contains(strings.ToUpper(p.Header.Get("Content-Transfer-Encoding")), "BASE64") {
uDec, _ = base64.StdEncoding.DecodeString(string(slurp))
} else if strings.Contains(strings.ToUpper(p.Header.Get("Content-Transfer-Encoding")), "QUOTED-PRINTABLE") {
uDec, _ = ioutil.ReadAll(quotedprintable.NewReader(strings.NewReader(string(slurp))))
} else {
uDec = []byte(string(slurp))
}
//fmt.Printf("%s %v\n", b, err)
//fmt.Printf("^^결과: Content-type: %s / Content-Transfer-encoding: \n --------\n %s\n", p.Header.Get("Content-Type"), uDec)
}
} else {
body, _ := ioutil.ReadAll(msg.Body)
if strings.Contains(strings.ToUpper(msg.Header.Get("Content-Transfer-encoding")), "BASE64") {
fmt.Println("1")
uDec, _ = base64.StdEncoding.DecodeString(string(body))
} else if strings.Contains(strings.ToUpper(msg.Header.Get("Content-Transfer-encoding")), "QUOTED-PRINTABLE") {
fmt.Println("2")
uDec, _ = ioutil.ReadAll(quotedprintable.NewReader(strings.NewReader(string(body))))
} else {
uDec = body
}
}
return string(uDec)
}
// decodeRFC2047 ... UTF8
func decodeRFC2047(s string) string {
// GO 1.5 does not decode headers, but this may change in future releases...
decoded, err := (&mime.WordDecoder{}).DecodeHeader(s)
if err != nil || len(decoded) == 0 {
return s
}
return decoded
}
// adapted from mime.randomBoundary
func randomString(length int) string {
buf := make([]byte, length)
_, err := io.ReadFull(rand.Reader, buf[:])
if err != nil {
panic(err)
}
return fmt.Sprintf("%x", buf[:])
}
POP3는 INBOX의 내용들만 읽을 수 있음.
IMAP처럼 폴더별 관리를 위해 DB나 파일로 저장하여 적용시켜야 함.
헤더에서 제목과 보낸사람, 받는 사람, 날짜 등을 추출.
바디에서 내용을 추출하는데 multipart 중에서 html 형식으로 내용이 들어 있는 것을 함수로 추출.
utf 디코딩은 가능하지만 euc-kr이나 이외의 인코딩에 대한 디코딩 함수 구현 필요.
'프로그래밍 > Golang' 카테고리의 다른 글
go-imap, charset 오류(ks_c_5601-1987 error) (0) | 2020.06.30 |
---|
댓글