CLI email sender

This commit is contained in:
Bel LaPointe
2019-07-03 11:48:52 -06:00
commit 4ca33e1c7b
50 changed files with 9996 additions and 0 deletions

21
vendor/github.com/taknb2nch/go-pop3/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Takanobu Hagino
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

115
vendor/github.com/taknb2nch/go-pop3/README.md generated vendored Normal file
View File

@@ -0,0 +1,115 @@
go-pop3
==========
This is a simple POP3 client package in Go language.
##Usage
```go
if err := pop3.ReceiveMail(address, user, pass,
func(number int, uid, data string, err error) (bool, error) {
log.Printf("%d, %s\n", number, uid)
// implement your own logic here
return false, nil
}); err != nil {
log.Fatalf("%v\n", err)
}
```
or use the method that implements the command
```go
client, err := pop3.Dial(address)
if err != nil {
log.Fatalf("Error: %v\n", err)
}
defer func() {
client.Quit()
client.Close()
}()
if err = client.User(user); err != nil {
log.Printf("Error: %v\n", err)
return
}
if err = client.Pass(pass); 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)
if count, size, err = client.List(6); err != nil {
log.Printf("Error: %v\n", err)
return
}
log.Printf("Number: %d, Size: %d\n", count, size)
var mis []pop3.MessageInfo
if mis, err = client.ListAll(); err != nil {
log.Printf("Error: %v\n", err)
return
}
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("Error: %v\n", err)
return
}
log.Printf("Number: %d, Uid: %s\n", number, uid)
if mis, err = client.UidlAll(); err != nil {
log.Printf("Error: %v\n", err)
return
}
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("Error: %v\n", err)
return
}
log.Printf("Content:\n%s\n", content)
if err = client.Dele(6); err != nil {
log.Printf("Error: %v\n", err)
return
}
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
}
```
##License
[MIT License](https://github.com/taknb2nch/go-pop3/blob/master/LICENSE)

400
vendor/github.com/taknb2nch/go-pop3/pop3.go generated vendored Normal file
View File

@@ -0,0 +1,400 @@
// Package pop3 provides simple POP3 client.
package pop3
import (
"errors"
"fmt"
"net"
"strconv"
"strings"
)
var (
EOF = errors.New("skip the all mail remaining")
)
// MessageInfo has Number, Size, and Uid fields,
// and used as a return value of ListAll and UidlAll.
// When used as the return value of the method ListAll,
// MessageInfo contain only the Number and Size values.
// When used as the return value of the method UidlAll,
// MessageInfo contain only the Number and Uid values.
type MessageInfo struct {
Number int
Size uint64
Uid string
}
// A Client represents a client connection to an POP server.
type Client struct {
// Text is the pop3.Conn used by the Client.
Text *Conn
// keep a reference to the connection so it can be used to create a TLS
// connection later
conn net.Conn
}
// Dial returns a new Client connected to an POP server at addr.
// The addr must include a port number.
func Dial(addr string) (*Client, error) {
conn, err := net.Dial("tcp", addr)
if err != nil {
return nil, err
}
return NewClient(conn)
}
// NewClient returns a new Client using an existing connection.
func NewClient(conn net.Conn) (*Client, error) {
text := NewConn(conn)
_, err := text.ReadResponse()
if err != nil {
return nil, err
}
return &Client{Text: text, conn: conn}, nil
}
// User issues a USER command to the server using the provided user name.
func (c *Client) User(user string) error {
return c.cmdSimple("USER %s", user)
}
// Pass issues a PASS command to the server using the provided password.
func (c *Client) Pass(pass string) error {
return c.cmdSimple("PASS %s", pass)
}
// Stat issues a STAT command to the server
// and returns mail count and total size.
func (c *Client) Stat() (int, uint64, error) {
return c.cmdStatOrList("STAT", "STAT")
}
// Retr issues a RETR command to the server using the provided mail number
// and returns mail data.
func (c *Client) Retr(number int) (string, error) {
var err error
err = c.Text.WriteLine("RETR %d", number)
if err != nil {
return "", err
}
_, err = c.Text.ReadResponse()
if err != nil {
return "", err
}
return c.Text.ReadToPeriod()
}
// List issues a LIST command to the server using the provided mail number
// and returns mail number and size.
func (c *Client) List(number int) (int, uint64, error) {
return c.cmdStatOrList("LIST", "LIST %d", number)
}
// List issues a LIST command to the server
// and returns array of MessageInfo.
func (c *Client) ListAll() ([]MessageInfo, error) {
list := make([]MessageInfo, 0)
err := c.cmdReadLines("LIST", func(line string) error {
number, size, err := c.convertNumberAndSize(line)
if err != nil {
return err
}
list = append(list, MessageInfo{Number: number, Size: size})
return nil
})
if err != nil {
return nil, err
}
return list, nil
}
// Uidl issues a UIDL command to the server using the provided mail number
// and returns mail number and unique id.
func (c *Client) Uidl(number int) (int, string, error) {
var err error
err = c.Text.WriteLine("UIDL %d", number)
if err != nil {
return 0, "", err
}
var msg string
msg, err = c.Text.ReadResponse()
if err != nil {
return 0, "", err
}
var val int
var uid string
val, uid, err = c.convertNumberAndUid(msg)
if err != nil {
return 0, "", err
}
return val, uid, nil
}
// Uidl issues a UIDL command to the server
// and returns array of MessageInfo.
func (c *Client) UidlAll() ([]MessageInfo, error) {
list := make([]MessageInfo, 0)
err := c.cmdReadLines("UIDL", func(line string) error {
number, uid, err := c.convertNumberAndUid(line)
if err != nil {
return err
}
list = append(list, MessageInfo{Number: number, Uid: uid})
return nil
})
if err != nil {
return nil, err
}
return list, nil
}
// Dele issues a DELE command to the server using the provided mail number.
func (c *Client) Dele(number int) error {
return c.cmdSimple("DELE %d", number)
}
// Noop issues a NOOP command to the server.
func (c *Client) Noop() error {
return c.cmdSimple("NOOP")
}
// Rset issues a RSET command to the server.
func (c *Client) Rset() error {
return c.cmdSimple("RSET")
}
// Quit issues a QUIT command to the server.
func (c *Client) Quit() error {
return c.cmdSimple("QUIT")
}
// ReceiveMail connects to the server at addr,
// and authenticates with user and pass,
// and calling receiveFn for each mail.
func ReceiveMail(addr, user, pass string, receiveFn ReceiveMailFunc) error {
c, err := Dial(addr)
if err != nil {
return err
}
defer func() {
if err != nil && err != EOF {
c.Rset()
}
c.Quit()
c.Close()
}()
if err = c.User(user); err != nil {
return err
}
if err = c.Pass(pass); err != nil {
return err
}
var mis []MessageInfo
if mis, err = c.UidlAll(); err != nil {
return err
}
for _, mi := range mis {
var data string
data, err = c.Retr(mi.Number)
del, err := receiveFn(mi.Number, mi.Uid, data, err)
if err != nil && err != EOF {
return err
}
if del {
if err = c.Dele(mi.Number); err != nil {
return err
}
}
if err == EOF {
break
}
}
return nil
}
// ReceiveMailFunc is the type of the function called for each mail.
// Its arguments are mail's number, uid, data, and mail receiving error.
// if this function returns false value, the mail will be deleted,
// if its returns EOF, skip the all mail of remaining.
// (after deleting mail, if necessary)
type ReceiveMailFunc func(number int, uid, data string, err error) (bool, error)
func (c *Client) cmdSimple(format string, args ...interface{}) error {
var err error
err = c.Text.WriteLine(format, args...)
if err != nil {
return err
}
_, err = c.Text.ReadResponse()
if err != nil {
return err
}
return nil
}
func (c *Client) cmdStatOrList(name, format string, args ...interface{}) (int, uint64, error) {
var err error
err = c.Text.WriteLine(format, args...)
if err != nil {
return 0, 0, err
}
var msg string
msg, err = c.Text.ReadResponse()
if err != nil {
return 0, 0, err
}
s := strings.Split(msg, " ")
if len(s) < 2 {
return 0, 0, ResponseError(fmt.Sprintf("invalid response format: %s", msg))
}
var val int
var size uint64
val, size, err = c.convertNumberAndSize(msg)
if err != nil {
return 0, 0, err
}
return val, size, nil
}
func (c *Client) cmdReadLines(cmnd string, lineFn lineFunc) error {
var err error
err = c.Text.WriteLine(cmnd)
if err != nil {
return err
}
_, err = c.Text.ReadResponse()
if err != nil {
return err
}
var lines []string
lines, err = c.Text.ReadLines()
if err != nil {
return err
}
for _, line := range lines {
err = lineFn(line)
if err != nil {
return err
}
}
return nil
}
type lineFunc func(line string) error
func (c *Client) Close() error {
return c.Text.Close()
}
func (c *Client) convertNumberAndSize(line string) (int, uint64, error) {
var err error
s := strings.Split(line, " ")
if len(s) < 2 {
return 0, 0, errors.New(fmt.Sprintf("the length of the array is less than 2: %s", line))
}
var val int
var size uint64
if val, err = strconv.Atoi(s[0]); err != nil {
return 0, 0, errors.New(fmt.Sprintf("can not convert element[0] to int type: %s", line))
}
if size, err = strconv.ParseUint(s[1], 10, 64); err != nil {
return 0, 0, errors.New(fmt.Sprintf("can not convert element[1] to uint64 type: %s", line))
}
return val, size, nil
}
func (c *Client) convertNumberAndUid(line string) (int, string, error) {
var err error
s := strings.Split(line, " ")
if len(s) < 2 {
return 0, "", errors.New(fmt.Sprintf("the length of the array is less than 2: %s", line))
}
var val int
if val, err = strconv.Atoi(s[0]); err != nil {
return 0, "", errors.New(fmt.Sprintf("can not convert element[0] to int type: %s", line))
}
return val, s[1], nil
}

175
vendor/github.com/taknb2nch/go-pop3/pop3proto.go generated vendored Normal file
View File

@@ -0,0 +1,175 @@
package pop3
import (
"bufio"
"fmt"
"io"
_ "log"
"net/textproto"
"strings"
)
// A ResponseError describes a protocol violation such as an invalid response or a hung-up connection.
type ResponseError string
func (r ResponseError) Error() string {
return string(r)
}
// A Conn represents a textual network protocol connection for POP3.
type Conn struct {
Reader
Writer
conn io.ReadWriteCloser
}
// NewConn returns a new Conn using conn for I/O.
func NewConn(conn io.ReadWriteCloser) *Conn {
return &Conn{
Reader: Reader{R: textproto.NewReader(bufio.NewReader(conn))},
Writer: Writer{W: bufio.NewWriter(conn)},
conn: conn,
}
}
// Close closes the connection.
func (c *Conn) Close() error {
return c.conn.Close()
}
// A Reader implements convenience methods
// for reading requests or responses from a text protocol network connection.
type Reader struct {
R *textproto.Reader
}
// NewReader returns a new Reader reading from r.
func NewReader(r *bufio.Reader) *Reader {
return &Reader{R: textproto.NewReader(r)}
}
// ReadLine reads a single line from r,
// eliding the final \n or \r\n from the returned string.
// This calls textproto.Reader.ReadLine simply.
func (r *Reader) ReadLine() (string, error) {
return r.R.ReadLine()
// for debug
// l, err := r.R.ReadLine()
// log.Printf("> %s\n", l)
// return l, err
}
// ReadLines reads a multiline until the last line of the only period,
// and returns a each line at slice.
// it does not contain last period.
func (r *Reader) ReadLines() ([]string, error) {
var lines []string
var line string
var err error
for {
line, err = r.R.ReadLine()
if err != nil {
return nil, err
}
if line == "." {
return lines, nil
}
lines = append(lines, line)
}
}
// ReadToPeriod reads a multiline until the last line of the only period,
// and returns as a string.
// it does not contain last period.
func (r *Reader) ReadToPeriod() (string, error) {
lines, err := r.ReadLines()
if err != nil {
return "", err
}
return strings.Join(lines, "\r\n"), nil
}
// ReadResponse reads a single line from r,
// and parses reponse.
// if the response is -ERR or has some other errors,
// it returns error.
func (r *Reader) ReadResponse() (string, error) {
line, err := r.ReadLine()
if err != nil {
return "", err
}
return r.parseResponse(line)
}
func (r *Reader) parseResponse(line string) (string, error) {
s := strings.ToUpper(line)
if s == "+OK" {
return "", nil
} else if strings.HasPrefix(s, "+OK ") {
return line[4:], nil
} else if s == "-ERR" {
return "", ResponseError("")
} else if strings.HasPrefix(s, "-ERR ") {
return "", ResponseError(line[5:])
} else {
return "", ResponseError(fmt.Sprintf("unknown response: %s", line))
}
}
var crnl = []byte{'\r', '\n'}
// A Writer implements convenience methods
// for writing requests or responses to a text protocol network connection.
type Writer struct {
W *bufio.Writer
}
// NewWriter returns a new Writer writing to w.
func NewWriter(w *bufio.Writer) *Writer {
return &Writer{W: w}
}
// WriteLine writes the formatted output followed by \r\n.
func (w *Writer) WriteLine(format string, args ...interface{}) error {
var err error
if _, err = fmt.Fprintf(w.W, format, args...); err != nil {
return err
}
if _, err = w.W.Write(crnl); err != nil {
return err
}
return w.W.Flush()
// for debug
// var err error
// l := fmt.Sprintf(format, args...)
// if _, err = fmt.Fprint(w.W, l); err != nil {
// return err
// }
// if _, err = w.W.Write(crnl); err != nil {
// return err
// }
// if err = w.W.Flush(); err != nil {
// return err
// }
// log.Printf("< %s\n", l)
// return nil
}