From 91d5de8da92e1a802037aa643267c356595d9c31 Mon Sep 17 00:00:00 2001 From: "Glenn Y. Rolland" Date: Wed, 22 Aug 2018 12:29:14 +0200 Subject: [PATCH] Finalize mail transfer --- cmd/trello2mail/email.go | 77 +++++++++++++++++++++++++----------- cmd/trello2mail/main.go | 20 ---------- cmd/trello2mail/transport.go | 27 ++++++++++--- cmd/trello2mail/trello.go | 64 +++++++++++++++++++----------- 4 files changed, 117 insertions(+), 71 deletions(-) diff --git a/cmd/trello2mail/email.go b/cmd/trello2mail/email.go index e7283f2..16ecfff 100644 --- a/cmd/trello2mail/email.go +++ b/cmd/trello2mail/email.go @@ -1,39 +1,72 @@ package main import ( -// "errors" -// "fmt" -// "log" -// "os" -// "strconv" -// "net" -// "net/mail" -// "net/smtp" + "strings" + // "errors" + "bytes" + "fmt" + "github.com/davecgh/go-spew/spew" + // "log" + // "os" + // "strconv" + // "net" + "net/mail" + // "net/smtp" ) -type MailHeaders map[string]string -type MailBody []string +type EmailHeaders map[string]string +type EmailBody string type EmailCtx struct { - Headers MailHeaders - Body MailBody + Headers EmailHeaders + Body EmailBody +} + +func (headers EmailHeaders) String() string { + var buffer bytes.Buffer + for k, v := range headers { + buffer.WriteString(fmt.Sprintf("%s: %s\r\n", k, v)) + } + return buffer.String() +} + +func (body EmailBody) String() string { + res := string(body) + if false { + spew.Dump(res) + } + return res } func NewEmail() *EmailCtx { - return &EmailCtx{} + email := EmailCtx{} + email.Headers = make(EmailHeaders) + return &email } -func (email *EmailCtx) MakeHeaders(config EmailConfig) (int, error) { +func encodeRFC2047(text string) string { + // use mail's rfc2047 to encode any string + addr := mail.Address{text, ""} + return strings.Trim(addr.String(), " \"<@>") +} + +func (email *EmailCtx) MakeHeaders(config EmailConfig) { + email.Headers["Return-Path"] = config.From email.Headers["From"] = config.From email.Headers["To"] = config.To - email.Headers["Subject"] = config.Subject - return 0, nil + email.Headers["Subject"] = encodeRFC2047(config.Subject) + // email.Headers["Content-Type"] = "text/plain; charset=\"us-ascii\";" + email.Headers["Content-Type"] = "text/plain; charset=\"utf-8\";" + email.Headers["Content-Transfer-Encoding"] = "base64" + email.Headers["MIME-Version"] = "1.0" + + return } -func (email *EmailCtx) MakeBody(content []string) (int, error) { - email.Body = content - return 0, nil -} - -func (email *EmailCtx) Send() { +func (email *EmailCtx) MakeBody(content string) { + email.Body = EmailBody(content) + if false { + spew.Dump(email.Body) + } + return } diff --git a/cmd/trello2mail/main.go b/cmd/trello2mail/main.go index 73a3b6b..c2b1322 100644 --- a/cmd/trello2mail/main.go +++ b/cmd/trello2mail/main.go @@ -1,28 +1,10 @@ package main -// Examples -// - Sending emails with SSL : https://gist.github.com/chrisgillis/10888032 -// - Project layout https://github.com/golang-standards/project-layout -// - Markdown rendering https://github.com/russross/blackfriday - import ( // "gopkg.in/russross/blackfriday.v2" // "github.com/davecgh/go-spew/spew" ) -func BuildContent(config Config) []string { - // run taskell (download tasks from trello and export markdown) - // read file as an array - // insert trello board url - // convert to HTML - - // output := blackfriday.Run(input, blackfriday.WithNoExtensions()) - return []string{} -} - -func ImportFromTrello() { -} - func main() { // Setup config config := NewConfig() @@ -32,13 +14,11 @@ func main() { trelloCtx := NewTrello(config.Trello.Token) trelloBoard := trelloCtx.GetBoard(config.Trello.Url) trelloMarkdown := trelloBoard.ExportToMarkdown() - panic("samere") // Create email enveloppe email := NewEmail() email.MakeHeaders(config.Email) email.MakeBody(trelloMarkdown) - email.Send() // Connect and send email transport := NewTransport(config.Smtp) diff --git a/cmd/trello2mail/transport.go b/cmd/trello2mail/transport.go index 99a05c1..534b711 100644 --- a/cmd/trello2mail/transport.go +++ b/cmd/trello2mail/transport.go @@ -1,7 +1,9 @@ package main import ( + "bytes" "crypto/tls" + "encoding/base64" "fmt" "log" "net/smtp" @@ -54,7 +56,6 @@ func NewTransportTls(config SmtpConfig) *tls.Config { func (ctx *TransportCtx) DialInsecure() { // no SSL/TLS - fmt.Println("Creating SMTP client...") c, err := smtp.Dial(ctx.Address) if err != nil { log.Panic(err) @@ -63,13 +64,11 @@ func (ctx *TransportCtx) DialInsecure() { } func (ctx *TransportCtx) DialTls() { - fmt.Printf("Creating TLS connection to %s...\n", ctx.Address) conn, err := tls.Dial("tcp", ctx.Address, ctx.Tls) if err != nil { log.Panic(err) } - fmt.Println("Creating SMTP client...") c, err := smtp.NewClient(conn, ctx.Config.Hostname) if err != nil { log.Panic(err) @@ -78,12 +77,10 @@ func (ctx *TransportCtx) DialTls() { } func (ctx *TransportCtx) DialStartTls() { - fmt.Println("Creating SMTP client...") c, err := smtp.Dial(ctx.Address) if err != nil { log.Panic(err) } - fmt.Printf("Creating StartTLS connection to %s...\n", ctx.Address) c.StartTLS(ctx.Tls) ctx.Client = c @@ -114,5 +111,25 @@ func (ctx *TransportCtx) Quit() { } func (ctx *TransportCtx) Send(email *EmailCtx) { + // Set email header + ctx.Client.Mail(email.Headers["From"]) + ctx.Client.Rcpt(email.Headers["To"]) + + // Set email body + wc, err := ctx.Client.Data() + if err != nil { + log.Panic(err) + } + defer wc.Close() + + var buffer bytes.Buffer + buffer.WriteString(email.Headers.String()) + buffer.WriteString("\r\n") + buffer.WriteString(base64.StdEncoding.EncodeToString([]byte(email.Body.String()))) + + if _, err = buffer.WriteTo(wc); err != nil { + log.Panic(err) + } + return } diff --git a/cmd/trello2mail/trello.go b/cmd/trello2mail/trello.go index 3d462d8..40bd81d 100644 --- a/cmd/trello2mail/trello.go +++ b/cmd/trello2mail/trello.go @@ -2,6 +2,7 @@ package main import ( // "errors" + "bytes" "fmt" "github.com/adlio/trello" // "github.com/davecgh/go-spew/spew" @@ -38,27 +39,27 @@ func runcmd(command string) string { return string(out) } +func GetTokenProcessMessage() string { + url := strings.Join([]string{ + "https://trello.com/1/authorize?expiration=never", + "name=taskell", + "scope=read", + "response_type=token", + fmt.Sprintf("key=%s", APP_KEY), + }, "&") + + text := strings.Join([]string{ + "Wrong TRELLO_TOKEN value. Please visit:", + url, + "When you have your access token, set TRELLO_TOKEN=", + }, "\n\n") + + return text +} + func NewTrello(token string) *TrelloCtx { client := trello.NewClient(APP_KEY, token) - /* - if client == nil { - url := strings.Join([]string{ - "https://trello.com/1/authorize?expiration=never", - "name=taskell", - "scope=read", - "response_type=token", - fmt.Sprintf("key=%s", APP_KEY), - }, "&") - text := strings.Join([]string{ - "Wrong TRELLO_TOKEN value. Please visit:", - url, - "When you have your access token, set TRELLO_TOKEN=", - }, "\n\n") - - log.Panic(errors.New(text)) - } - */ ctx := TrelloCtx{} ctx.Token = token ctx.Client = client @@ -79,16 +80,31 @@ func (ctx *TrelloCtx) GetBoard(boardUrl string) TrelloBoard { return TrelloBoard{Ctx: ctx, Ptr: board} } -func (board *TrelloBoard) ExportToMarkdown() []string { - // var s []string +func (board *TrelloBoard) ExportToMarkdown() string { + var markdown bytes.Buffer + var text string lists, _ := board.Ptr.GetLists(trello.Defaults()) // spew.Dump(lists) - // s = append(s, "# Trello board") - for _, v := range lists { - fmt.Println(v.Name) + text = fmt.Sprintf("# Board %s\n\n", board.Ptr.Name) + markdown.WriteString(text) + + text = fmt.Sprintf("URL: %s\n", board.Ptr.ShortUrl) + markdown.WriteString(text) + + for listIdx := len(lists) - 1; listIdx >= 0; listIdx -= 1 { + list := lists[listIdx] + text := fmt.Sprintf("\n## %s\n\n", list.Name) + markdown.WriteString(text) + + cards, _ := list.GetCards(trello.Defaults()) + for _, card := range cards { + text := fmt.Sprintf("* %s\n", card.Name) + markdown.WriteString(text) + // spew.Dump(card) + } } - return []string{} + return markdown.String() } /*