M cmd/mb/main.go +14 -2
@@ 252,8 252,20 @@ func main() {
// todo: implement this
err = errors.New(cmd + ": not implemented")
case "send":
- // todo: dont forget to strip bcc header
- err = errors.New(cmd + ": not implemented")
+ var src io.ReadCloser = os.Stdin
+ if len(os.Args) > 2 {
+ if src, err = openMsg(mbox, os.Args[2]); err != nil {
+ break
+ }
+ }
+ var msg *mail.Message
+ if msg, err = mail.ReadMessage(src); err != nil {
+ src.Close()
+ break
+ }
+ if err = mb.Send(msg); err != nil {
+ // todo: move msg from draft to sent
+ }
case "mv":
// todo: defaultfolder
if len(os.Args) < 4 {
M command.go +4 -0
@@ 161,3 161,7 @@ func View(dst io.Writer, msg *mail.Messa
}
return parse(msg, newPlainTextPrinter(dst, transform.Nop))
}
+
+func Send(msg *mail.Message) error {
+ return sendWithSsmtp(msg, sendmailConfig)
+}
M config.go +3 -0
@@ 44,4 44,7 @@ var (
defaultFolderType = inbox
listDelim = " | "
+
+ // todo:
+ sendmailConfig = "/home/schlichti/.etc/ssmtp/mailbox.gmx.conf"
)
M edit.go +0 -1
@@ 420,7 420,6 @@ func (w *lineWriter) Write(b []byte) (in
return n, err
}
-// todo: dont write bcc when sending
func writeHeader(dst io.Writer, h map[string][]string) error {
enc := mime.QEncoding
var b bytes.Buffer
M parse.go +2 -2
@@ 59,9 59,9 @@ func mimeDecoder(p part) (io.Reader, err
// but we are save, as multipart.Part removes silently this
// header key, so this case cannot happen. still this feels fragile.
// see // http://golang.org/src/mime/multipart/multipart.go
- out = qp.NewReader(out)
+ out = qp.NewReader(p.Body)
case "base64":
- out = base64.NewDecoder(base64.StdEncoding, out)
+ out = base64.NewDecoder(base64.StdEncoding, p.Body)
default:
// "7bit", "8bit", "binary" and none-mime emails: nothing to do
out = p.Body
M send.go +23 -22
@@ 1,36 1,45 @@
package mailbox
import (
+ "fmt"
"io"
- qp "mime/quotedprintable"
- "net/textproto"
+ "net/mail"
"os"
"os/exec"
"strings"
)
-func ssmtpSender(header textproto.MIMEHeader, body io.Reader) error {
+func sendWithSsmtp(msg *mail.Message, configfile string) error {
- rcpts := append(extract(header.Get("To")), extract(header.Get("Cc"))...)
- rcpts = append(rcpts, extract(header.Get("Bcc"))...)
+ h := msg.Header
+ var rcpts []string
+ for _, key := range []string{"To", "Cc", "Bcc"} {
+ if rcpt := extract(h.Get(key)); len(rcpt) > 0 {
+ rcpts = append(rcpts, rcpt...)
+ }
+ }
+ delete(msg.Header, "Bcc")
// todo: remove -v
- args := append([]string{"-v", "-C", "/home/schlichti/.etc/ssmtp/gmx.conf"}, rcpts...)
+ args := append([]string{"-v", "-C", configfile}, rcpts...)
+ fmt.Fprintf(os.Stderr, "%q", args)
cmd := exec.Command("/usr/sbin/ssmtp", args...)
// todo: maybe use a pipe for both outputs?
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
stdin, err := cmd.StdinPipe()
+ if err != nil {
+ return err
+ }
+ defer stdin.Close()
if err := cmd.Start(); err != nil {
// todo: check when the error here occurs, like use a non existing prog
return err
}
- // todo: encode and write header (except bcc)
- // todo: remove bcc
- // finish header
- stdin.Write([]byte{'\n'})
+ // write header
+ if err = writeHeader(stdin, msg.Header); err != nil {
+ return err
+ }
// write body
- // todo: attachments, text quoted, others base64
- if _, err = io.Copy(stdin, qp.NewReader(body)); err != nil {
- // todo: clean up
+ if _, err = io.Copy(stdin, msg.Body); err != nil {
return err
}
// close stdin so the command can exit
@@ 38,15 47,7 @@ func ssmtpSender(header textproto.MIMEHe
// really return? first cmd.Wait() maybe?
return err
}
- if err := cmd.Wait(); err != nil {
- return err
- }
- return nil
-
-}
-
-func ssmtp() (func(textproto.MIMEHeader, io.Reader) error, error) {
- return nil, nil
+ return cmd.Wait()
}
func extract(list string) (addrs []string) {