Example #1
0
// Handler is the main loop that handles incoming mail - It satisfies the DeliverFunc
// interface required by imapclient but is a method attached to a set of rich state
// objects.
func (eng *Engine) Handler(r io.ReadSeeker, uid uint32, sha1 []byte) error {
	thismail, err := email.NewEmailFromReader(r)
	if err != nil {
		r.Seek(0, 0)
		ioutil.ReadAll(r)
		erroneousBody, err2 := ioutil.ReadAll(r)
		if err2 != nil {
			panic("Error getting body from bad email, to report actual error: " + err2.Error())
		}
		log15.Error("Received email but failed to parse", log15.Ctx{"context": "imap", "error": err, "email": string(erroneousBody)})
		return err
	}
	// Check for header indicating this was sent BY the list to itself (common pattern)
	if thismail.Headers.Get("sent-from-listless") == eng.Config.ListAddress {
		log15.Info("Received mail with a sent-from-listless header matching own. Ignoring.", log15.Ctx{"context": "imap"})
		return nil
	}
	log15.Info("Received mail addressed to..", log15.Ctx{"context": "imap", "to": strings.Join(thismail.To, ", ")})
	luaMail := WrapEmail(thismail)
	if luaMail == nil || !luaMail.isValid() {
		log15.Error("Received email but failed to wrap", log15.Ctx{"context": "imap", "error": ErrEmailInvalid, "email": thismail})
		return ErrEmailInvalid
	}
	log15.Info("Email about to be processed", log15.Ctx{"context": "imap", "email": luaMail})
	ok, err := eng.ProcessMail(luaMail)
	if err != nil {
		log15.Error("Error calling ProcessMail handler", log15.Ctx{"context": "lua", "error": err})
		return err
	}
	if !ok {
		log15.Debug("No error occurred, but not sending message on instruction from Lua", log15.Ctx{"context": "smtp"})
		return nil
	}
	// Verify that using the actual sender is OK according to SPF records for
	// sender Domain, otherwise fall back to list address.
	newSender := eng.ChooseListSenderEmail(luaMail.Sender)
	if newSender != luaMail.Sender {
		log15.Info("Outgoing email sender changed for SPF policy", log15.Ctx{"context": "smtp", "original": luaMail.Sender, "new": newSender})
	}
	luaMail.Email.From = newSender
	log15.Info("Outgoing email", log15.Ctx{"context": "smtp", "subject": luaMail.Subject})
	// Set header to indicate that this was sent by Listless, in case it loops around
	// somehow (some lists retain the "To: <*****@*****.**>" header unchanged).
	luaMail.Headers.Set("sent-from-listless", eng.Config.ListAddress)
	auth := smtp.PlainAuth("", eng.Config.SMTPUsername, eng.Config.SMTPPassword, eng.Config.SMTPHost)
	//auth := smtp.PlainAuth(eng.Config.SMTPUsername, eng.Config.SMTPUsername, eng.Config.SMTPPassword, eng.Config.SMTPHost)
	// Patched to allow excluding of variadic emails added after auth.
	err = luaMail.Send(eng.Config.smtpAddr, auth, eng.Config.ListAddress)
	if err != nil {
		log15.Error("Error sending message by SMTP", log15.Ctx{"context": "smtp", "error": err})
		return err
	}
	log15.Info("Sent message successfully", log15.Ctx{"context": "smtp", "subject": luaMail.Subject})
	return nil
}
Example #2
0
// API_Import_Email allows for the importing of email.
// Returns a Message object
func API_Import_Email(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		JSONResponse(w, models.Response{Success: false, Message: "Method not allowed"}, http.StatusBadRequest)
		return
	}
	ir := struct {
		Content      string `json:"content"`
		ConvertLinks bool   `json:"convert_links"`
	}{}
	err := json.NewDecoder(r.Body).Decode(&ir)
	if err != nil {
		JSONResponse(w, models.Response{Success: false, Message: "Error decoding JSON Request"}, http.StatusBadRequest)
		return
	}
	e, err := email.NewEmailFromReader(strings.NewReader(ir.Content))
	if err != nil {
		Logger.Println(err)
	}
	// If the user wants to convert links to point to
	// the landing page, let's make it happen by changing up
	// e.HTML
	if ir.ConvertLinks {
		d, err := goquery.NewDocumentFromReader(bytes.NewReader(e.HTML))
		if err != nil {
			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusBadRequest)
			return
		}
		d.Find("a").Each(func(i int, a *goquery.Selection) {
			a.SetAttr("href", "{{.URL}}")
		})
		h, err := d.Html()
		if err != nil {
			JSONResponse(w, models.Response{Success: false, Message: err.Error()}, http.StatusInternalServerError)
			return
		}
		e.HTML = []byte(h)
	}
	er := emailResponse{
		Subject: e.Subject,
		Text:    string(e.Text),
		HTML:    string(e.HTML),
	}
	JSONResponse(w, er, http.StatusOK)
	return
}
Example #3
0
File: api.go Project: 4D5A/gophish
// API_Import_Email allows for the importing of email.
// Returns a Message object
func API_Import_Email(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		JSONResponse(w, models.Response{Success: false, Message: "Method not allowed"}, http.StatusBadRequest)
		return
	}
	defer r.Body.Close()
	e, err := email.NewEmailFromReader(r.Body)
	if err != nil {
		Logger.Println(err)
	}
	er := emailResponse{
		Subject: e.Subject,
		Text:    string(e.Text),
		HTML:    string(e.HTML),
	}
	JSONResponse(w, er, http.StatusOK)
	return
}
Example #4
0
func (g *Gmuch) getMessage(m *notmuch.Message) (*model.Message, error) {
	msg := &model.Message{
		ID:       m.ID(),
		ThreadID: m.ThreadID(),
		Emails:   make([]*email.Email, 0, 1),
	}

	var fn string
	fns := m.Filenames()
	for fns.Next(&fn) {
		f, err := os.Open(fn)
		if err != nil {
			g.logger.Log(
				"method", "getMessage",
				"messageID", msg.ID,
				"operation", "open email file",
				"path", fn,
				"error", err,
			)
			return nil, err
		}
		defer f.Close()
		e, err := email.NewEmailFromReader(f)
		if err != nil {
			g.logger.Log(
				"method", "getMessage",
				"messageID", msg.ID,
				"operation", "parse email file",
				"path", fn,
				"error", err,
			)
			return nil, err
		}
		msg.Emails = append(msg.Emails, e)
	}

	tags := m.Tags()
	tag := &notmuch.Tag{}
	for tags.Next(tag) {
		msg.Tags = append(msg.Tags, tag.String())
	}

	return msg, nil
}