Add mailing sending feature for Anson Chen :)

This commit is contained in:
Chun-Hung Tseng
2023-07-16 21:56:44 +02:00
parent 8d7db1ea7b
commit a33d554f70

198
mail.go Normal file
View File

@@ -0,0 +1,198 @@
package proton_api_bridge
import (
"context"
"encoding/base64"
"io/ioutil"
"log"
"net/mail"
"path/filepath"
"github.com/ProtonMail/gluon/rfc822"
"github.com/ProtonMail/gopenpgp/v2/crypto"
"github.com/henrybear327/go-proton-api"
)
type MailSendingParameters struct {
TemplateFile string
EmailSubject string
RecipientEmailAddress string
EmailAttachments []string
EmailContentIDs []string
}
func (protonDrive *ProtonDrive) SendEmail(ctx context.Context, i int, errChan chan error, config *MailSendingParameters) {
log.Println("SendEmail in", i)
defer log.Println("SendEmail out", i)
createDraftResp, err := protonDrive.createDraft(ctx, config)
if err != nil {
errChan <- err
}
attachments, err := protonDrive.uploadAttachments(ctx, createDraftResp, config)
if err != nil {
errChan <- err
}
err = protonDrive.sendDraft(ctx, createDraftResp.ID, attachments, config)
if err != nil {
errChan <- err
}
errChan <- nil
}
func (protonDrive *ProtonDrive) getHTMLBody(config *MailSendingParameters) ([]byte, error) {
htmlTemplate, err := ioutil.ReadFile(config.TemplateFile)
if err != nil {
return nil, err
}
return htmlTemplate, nil
}
func (protonDrive *ProtonDrive) createDraft(ctx context.Context, config *MailSendingParameters) (*proton.Message, error) {
htmlTemplate, err := protonDrive.getHTMLBody(config)
if err != nil {
return nil, err
}
createDraftReq := proton.CreateDraftReq{
Message: proton.DraftTemplate{
Subject: config.EmailSubject,
Sender: &mail.Address{
Address: protonDrive.signatureAddress,
},
ToList: []*mail.Address{
{
Address: config.RecipientEmailAddress,
},
},
CCList: []*mail.Address{},
BCCList: []*mail.Address{},
Body: string(htmlTemplate), // NOTE: the body here is for yourself to view it! No sender encryption is done yet
MIMEType: rfc822.TextHTML,
// Unread: false,
// ExternalID: "", // FIXME: what's this
},
}
createDraftResp, err := protonDrive.c.CreateDraft(ctx, protonDrive.AddrKR, createDraftReq)
if err != nil {
return nil, err
}
return &createDraftResp, nil
}
func (protonDrive *ProtonDrive) getAttachmentSessionKeyMap(attachments []*proton.Attachment) (map[string]*crypto.SessionKey, error) {
ret := make(map[string]*crypto.SessionKey)
for i := range attachments {
keyPacket, err := base64.StdEncoding.DecodeString(attachments[i].KeyPackets)
if err != nil {
return nil, err
}
key, err := protonDrive.AddrKR.DecryptSessionKey(keyPacket)
if err != nil {
return nil, err
}
ret[attachments[i].ID] = key
}
return ret, nil
}
func (protonDrive *ProtonDrive) uploadAttachments(ctx context.Context, createDraftResp *proton.Message, config *MailSendingParameters) ([]*proton.Attachment, error) {
attachments := make([]*proton.Attachment, 0)
for i := range config.EmailAttachments {
// read out attachment file
fileByteArray, err := ioutil.ReadFile(config.EmailAttachments[i])
if err != nil {
return nil, err
}
req := proton.CreateAttachmentReq{
MessageID: createDraftResp.ID,
Filename: filepath.Base(config.EmailAttachments[i]),
MIMEType: rfc822.MultipartMixed, // FIXME: what is this?
Disposition: proton.InlineDisposition,
ContentID: config.EmailContentIDs[i],
Body: fileByteArray,
}
uploadAttachmentResp, err := protonDrive.c.UploadAttachment(ctx, protonDrive.AddrKR, req)
if err != nil {
return nil, err
}
// log.Printf("uploadAttachmentResp %#v", uploadAttachmentResp)
attachments = append(attachments, &uploadAttachmentResp)
}
return attachments, nil
}
func (protonDrive *ProtonDrive) sendDraft(ctx context.Context, messageID string, attachents []*proton.Attachment, config *MailSendingParameters) error {
// FIXME: repect all sendPrefs
// FIXME: respect PGPMIMEScheme, etc.
recipientPublicKeys, recipientType, err := protonDrive.c.GetPublicKeys(ctx, config.RecipientEmailAddress)
if err != nil {
return err
}
if recipientType != proton.RecipientTypeInternal {
log.Fatalln("Currently only support internal email sending")
}
recipientKR, err := recipientPublicKeys.GetKeyRing()
if err != nil {
return err
}
htmlTemplate, err := protonDrive.getHTMLBody(config)
if err != nil {
return err
}
atts, err := protonDrive.getAttachmentSessionKeyMap(attachents)
if err != nil {
return err
}
// send email
sendReq := proton.SendDraftReq{
// Packages: []*proton.MessagePackage{},
}
// for each of the recipient, we encrypt body for them
if err = sendReq.AddTextPackage(protonDrive.AddrKR,
string(htmlTemplate),
rfc822.TextHTML,
map[string]proton.SendPreferences{config.RecipientEmailAddress: {
Encrypt: true,
PubKey: recipientKR,
SignatureType: proton.DetachedSignature,
EncryptionScheme: proton.InternalScheme,
MIMEType: rfc822.TextHTML, // FIXME
}},
atts,
); err != nil {
return err
}
/* msg */
_, err = protonDrive.c.SendDraft(ctx, messageID, sendReq)
if err != nil {
return err
}
// log.Println(msg)
return nil
}