CLI email sender
This commit is contained in:
21
vendor/github.com/taknb2nch/go-pop3/LICENSE
generated
vendored
Normal file
21
vendor/github.com/taknb2nch/go-pop3/LICENSE
generated
vendored
Normal 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
115
vendor/github.com/taknb2nch/go-pop3/README.md
generated
vendored
Normal 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
400
vendor/github.com/taknb2nch/go-pop3/pop3.go
generated
vendored
Normal 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
175
vendor/github.com/taknb2nch/go-pop3/pop3proto.go
generated
vendored
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user