contact/.email.go

331 lines
6.4 KiB
Go
Executable File

package contact
import (
"crypto/tls"
"fmt"
"gitea.inhome.blapointe.com/local/system/sysconf"
"log"
"net"
"net/smtp"
"regexp"
"strings"
"time"
pop3 "github.com/taknb2nch/go-pop3"
)
// Emailer allows sending of emails (or better
// texts with the right address) with TLS.
type Emailer interface {
Send(string, string) error
Check() []Email
}
type emailer struct {
to string
from string
smtpServer string
pop3Server string
pwd string
}
type Email struct {
To string
From string
Date time.Time
Subject string
Body string
}
func (e Email) String() string {
return fmt.Sprintf("To: %q\nFrom: %q\nSubj: %q\nDate: %q\nBody: %q", e.To, e.From, e.Subject, e.Date.String(), e.Body)
}
// NewEmailer returns a emailer capable of Send()ing
// To the given address.
func NewEmailer(To string) Emailer {
config := sysconf.Get("email")
return &emailer{
smtpServer: config.IP,
pop3Server: config.IP2,
to: To,
from: config.Log,
pwd: config.Port,
}
}
// Send sends an email To the configured address with
// the given Subject and message.
func (e *emailer) Send(subj, msg string) error {
// Setup headers
headers := make(map[string]string)
headers["From"] = e.from
headers["To"] = e.to
headers["Subject"] = subj
Body := ""
for k, v := range headers {
Body += fmt.Sprintf("%s: %s\r\n", k, v)
}
Body += "\r\n" + msg
// Connect To the SMTP Server
c := e.newSmtpClient()
defer c.Quit()
// To && From
if err := c.Mail(e.from); err != nil {
log.Panic(err)
}
if err := c.Rcpt(e.to); err != nil {
log.Panic(err)
}
// Data
w, err := c.Data()
if err != nil {
log.Panic(err)
}
_, err = w.Write([]byte(Body))
if err != nil {
log.Panic(err)
}
err = w.Close()
if err != nil {
log.Panic(err)
}
return nil
}
func (e *emailer) newSmtpClient() *smtp.Client {
host, _, _ := net.SplitHostPort(e.smtpServer)
auth := smtp.PlainAuth("", e.from, e.pwd, host)
conn := e.getConn(e.smtpServer)
c, err := smtp.NewClient(conn, host)
if err != nil {
log.Panic(err)
}
// Auth
if err = c.Auth(auth); err != nil {
log.Panic(err)
}
return c
}
func (e *emailer) getConn(remote string) net.Conn {
host, _, _ := net.SplitHostPort(remote)
tlsconfig := &tls.Config{
InsecureSkipVerify: true,
ServerName: host,
}
// Here is the key, you need To call tls.Dial instead of smtp.Dial
// for smtp servers running on 465 that require an ssl connection
// From the very beginning (no starttls)
conn, err := tls.Dial("tcp", remote, tlsconfig)
if err != nil {
log.Panic(err)
}
return conn
}
func (e *emailer) newPop3Client() *pop3.Client {
conn := e.getConn(e.pop3Server)
client, err := pop3.NewClient(conn)
if err != nil {
log.Fatalf("Dial Error: %v\n", err)
}
if err = client.User(e.from); err != nil {
log.Panicf("User Error: %v\n", err)
}
if err = client.Pass(e.pwd); err != nil {
log.Panicf("Pass Error: %v\n", err)
}
return client
}
func (e *emailer) Check() []Email {
client := e.newPop3Client()
defer func() {
client.Quit()
client.Close()
}()
var count int
var err error
if count, _, err = client.Stat(); err != nil {
log.Printf("Stat Error: %v\n", err)
return nil
}
var content string
emails := make([]Email, count)
for i := 1; i <= count; i++ {
if content, err = client.Retr(i); err != nil {
log.Printf("Retr Error: %v\n", err)
return nil
}
emails[i-1] = parseEmail(content)
}
return emails
}
func (e *emailer) pop3all() []Email {
conn := e.getConn(e.pop3Server)
client, err := pop3.NewClient(conn)
if err != nil {
log.Fatalf("Dial Error: %v\n", err)
}
defer func() {
client.Quit()
client.Close()
}()
if err = client.User(e.from); err != nil {
log.Printf("User Error: %v\n", err)
return nil
}
if err = client.Pass(e.pwd); err != nil {
log.Printf("Pass Error: %v\n", err)
return nil
}
var count int
var size uint64
if count, size, err = client.Stat(); err != nil {
log.Printf("Stat Error: %v\n", err)
return nil
}
log.Printf("Count: %d, Size: %d\n", count, size)
if count, size, err = client.List(6); err != nil {
log.Printf("List Error: %v\n", err)
return nil
}
log.Printf("Number: %d, Size: %d\n", count, size)
var mis []pop3.MessageInfo
if mis, err = client.ListAll(); err != nil {
log.Printf("LAll Error: %v\n", err)
return nil
}
for _, mi := range mis {
log.Printf("Number: %d, Size: %d\n", mi.Number, mi.Size)
}
var number int
var uid string
if number, uid, err = client.Uidl(6); err != nil {
log.Printf("Uidl Error: %v\n", err)
return nil
}
log.Printf("Number: %d, Uid: %s\n", number, uid)
if mis, err = client.UidlAll(); err != nil {
log.Printf("UAll Error: %v\n", err)
return nil
}
for _, mi := range mis {
log.Printf("Number: %d, Uid: %s\n", mi.Number, mi.Uid)
}
var content string
if content, err = client.Retr(8); err != nil {
log.Printf("Retr Error: %v\n", err)
return nil
}
log.Printf("Content:\n%s\n", content)
/*
if err = client.Dele(6); err != nil {
log.Printf("Dele Error: %v\n", err)
return nil
}
*/
if err = client.Noop(); err != nil {
log.Printf("Noop Error: %v\n", err)
return nil
}
if err = client.Rset(); err != nil {
log.Printf("Rset Error: %v\n", err)
return nil
}
return nil
}
/*
type Email struct {
To string
From string
Date time.Time
Subject string
Body string
}
*/
func parseEmail(content string) Email {
To := regexp.MustCompile("\n[Tt]o: .*\n").FindString(content)
To = strings.TrimSpace(To)
To = strings.Trim(To, "TTo")
To = strings.Trim(To, ": {}<>")
Subject := regexp.MustCompile("\n[Ss]ubject: .*\n").FindString(content)
Subject = strings.TrimSpace(Subject)
Subject = strings.Trim(Subject, "SSubject")
Subject = strings.Trim(Subject, ": ")
when := regexp.MustCompile("[Dd]ate: .*\n").FindString(content)
when = strings.Trim(when, "DDate")
when = strings.Trim(when, ":")
when = strings.TrimSpace(when)
Date, err := time.Parse("Mon, 2 Jan 2006 15:04:05 -0700 (MST)", when)
if err != nil {
log.Println(err)
}
parseFrom := regexp.MustCompile("[^ ]*@[^ ]*")
From := regexp.MustCompile("\n[Ff]rom: .*\n").FindString(content)
From = strings.TrimSpace(From)
From = parseFrom.FindString(From)
From = strings.Trim(From, "<>{}")
Body := ""
Bodyarr := strings.Split(content, "\n")
Body = Bodyarr[len(Bodyarr)-1]
return Email{
To: To,
From: From,
Date: Date,
Subject: Subject,
Body: Body,
}
}