mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
webapi: implement adding "alternative files" to messages sent with the Send method
with new field "AlternativeFiles" in the JSON body, or with "alternativefile" form file uploads. can be used if there is a (full) alternative representation (alternative to text and/or html part), like a calendar item, or PDF file. for issue #188 by morki
This commit is contained in:
parent
62bd2f4427
commit
6c488ead0b
4 changed files with 40 additions and 11 deletions
|
@ -114,10 +114,10 @@ func badResponse(hresp *http.Response) error {
|
||||||
// Configure webhooks to receive updates about deliveries.
|
// Configure webhooks to receive updates about deliveries.
|
||||||
//
|
//
|
||||||
// If the request is a multipart/form-data, uploaded files with the form keys
|
// If the request is a multipart/form-data, uploaded files with the form keys
|
||||||
// "inlinefile" and/or "attachedfile" will be added to the message. If the uploaded
|
// "alternativefile", "inlinefile" and/or "attachedfile" will be added to the
|
||||||
// file has content-type and/or content-id headers, they will be included. If no
|
// message. If the uploaded file has content-type and/or content-id headers, they
|
||||||
// content-type is present in the request, and it can be detected, it is included
|
// will be included. If no content-type is present in the request, and it can be
|
||||||
// automatically.
|
// detected, it is included automatically.
|
||||||
//
|
//
|
||||||
// Example call with a text and html message, with an inline and an attached image:
|
// Example call with a text and html message, with an inline and an attached image:
|
||||||
//
|
//
|
||||||
|
|
|
@ -115,6 +115,11 @@ type SendRequest struct {
|
||||||
// Unless a User-Agent or X-Mailer header is present, a User-Agent is added.
|
// Unless a User-Agent or X-Mailer header is present, a User-Agent is added.
|
||||||
Headers [][2]string
|
Headers [][2]string
|
||||||
|
|
||||||
|
// Alternative files are added as (full) alternative representation of the text
|
||||||
|
// and/or html parts. Alternative files cause a part with content-type
|
||||||
|
// "multipart/alternative" to be added to the message. Optional.
|
||||||
|
AlternativeFiles []File
|
||||||
|
|
||||||
// Inline files are added to the message and should be displayed by mail clients as
|
// Inline files are added to the message and should be displayed by mail clients as
|
||||||
// part of the message contents. Inline files cause a part with content-type
|
// part of the message contents. Inline files cause a part with content-type
|
||||||
// "multipart/related" to be added to the message. Optional.
|
// "multipart/related" to be added to the message. Optional.
|
||||||
|
|
|
@ -759,8 +759,9 @@ func (s server) Send(ctx context.Context, req webapi.SendRequest) (resp webapi.S
|
||||||
xc.Header("User-Agent", "mox/"+moxvar.Version)
|
xc.Header("User-Agent", "mox/"+moxvar.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whether we have additional separately inline/attached file(s).
|
// Whether we have additional separately alternative/inline/attached file(s).
|
||||||
mpf := reqInfo.Request.MultipartForm
|
mpf := reqInfo.Request.MultipartForm
|
||||||
|
formAlternative := mpf != nil && len(mpf.File["alternativefile"]) > 0
|
||||||
formInline := mpf != nil && len(mpf.File["inlinefile"]) > 0
|
formInline := mpf != nil && len(mpf.File["inlinefile"]) > 0
|
||||||
formAttachment := mpf != nil && len(mpf.File["attachedfile"]) > 0
|
formAttachment := mpf != nil && len(mpf.File["attachedfile"]) > 0
|
||||||
|
|
||||||
|
@ -770,6 +771,7 @@ func (s server) Send(ctx context.Context, req webapi.SendRequest) (resp webapi.S
|
||||||
// - multipart/alternative (in case we have both text and html bodies)
|
// - multipart/alternative (in case we have both text and html bodies)
|
||||||
// - text/plain (optional)
|
// - text/plain (optional)
|
||||||
// - text/html (optional)
|
// - text/html (optional)
|
||||||
|
// - alternative file, ...
|
||||||
// - inline file, ...
|
// - inline file, ...
|
||||||
// - attached file, ...
|
// - attached file, ...
|
||||||
|
|
||||||
|
@ -811,7 +813,7 @@ func (s server) Send(ctx context.Context, req webapi.SendRequest) (resp webapi.S
|
||||||
related = xcreateMultipart("related")
|
related = xcreateMultipart("related")
|
||||||
cur = related
|
cur = related
|
||||||
}
|
}
|
||||||
if m.Text != "" && m.HTML != "" {
|
if m.Text != "" && m.HTML != "" || len(req.AlternativeFiles) > 0 || formAlternative {
|
||||||
alternative = xcreateMultipart("alternative")
|
alternative = xcreateMultipart("alternative")
|
||||||
cur = alternative
|
cur = alternative
|
||||||
}
|
}
|
||||||
|
@ -827,10 +829,6 @@ func (s server) Send(ctx context.Context, req webapi.SendRequest) (resp webapi.S
|
||||||
_, err := tp.Write([]byte(htmlBody))
|
_, err := tp.Write([]byte(htmlBody))
|
||||||
xcheckf(err, "write html part")
|
xcheckf(err, "write html part")
|
||||||
}
|
}
|
||||||
if alternative != nil {
|
|
||||||
alternative.Close()
|
|
||||||
alternative = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
xaddFileBase64 := func(ct string, inline bool, filename string, cid string, base64Data string) {
|
xaddFileBase64 := func(ct string, inline bool, filename string, cid string, base64Data string) {
|
||||||
h := textproto.MIMEHeader{}
|
h := textproto.MIMEHeader{}
|
||||||
|
@ -923,6 +921,18 @@ func (s server) Send(ctx context.Context, req webapi.SendRequest) (resp webapi.S
|
||||||
xcheckf(err, "flushing uploaded file")
|
xcheckf(err, "flushing uploaded file")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cur = alternative
|
||||||
|
xaddJSONFiles(req.AlternativeFiles, true)
|
||||||
|
if mpf != nil {
|
||||||
|
for _, fh := range mpf.File["alternativefile"] {
|
||||||
|
xaddFile(fh, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if alternative != nil {
|
||||||
|
alternative.Close()
|
||||||
|
alternative = nil
|
||||||
|
}
|
||||||
|
|
||||||
cur = related
|
cur = related
|
||||||
xaddJSONFiles(req.InlineFiles, true)
|
xaddJSONFiles(req.InlineFiles, true)
|
||||||
if mpf != nil {
|
if mpf != nil {
|
||||||
|
|
|
@ -181,6 +181,13 @@ func TestServer(t *testing.T) {
|
||||||
},
|
},
|
||||||
Extra: map[string]string{"a": "123"},
|
Extra: map[string]string{"a": "123"},
|
||||||
Headers: [][2]string{{"x-custom", "header"}},
|
Headers: [][2]string{{"x-custom", "header"}},
|
||||||
|
AlternativeFiles: []webapi.File{
|
||||||
|
{
|
||||||
|
Name: "x.ics",
|
||||||
|
ContentType: "text/calendar",
|
||||||
|
Data: base64.StdEncoding.EncodeToString([]byte("ics data...")),
|
||||||
|
},
|
||||||
|
},
|
||||||
InlineFiles: []webapi.File{
|
InlineFiles: []webapi.File{
|
||||||
{
|
{
|
||||||
Name: "x.png",
|
Name: "x.png",
|
||||||
|
@ -228,8 +235,15 @@ func TestServer(t *testing.T) {
|
||||||
sendReqBuf, err := json.Marshal(fdSendReq)
|
sendReqBuf, err := json.Marshal(fdSendReq)
|
||||||
tcheckf(t, err, "send request")
|
tcheckf(t, err, "send request")
|
||||||
mp.WriteField("request", string(sendReqBuf))
|
mp.WriteField("request", string(sendReqBuf))
|
||||||
|
|
||||||
|
// One alternative file.
|
||||||
|
pw, err := mp.CreateFormFile("alternativefile", "test.ics")
|
||||||
|
tcheckf(t, err, "create alternative ics file")
|
||||||
|
_, err = fmt.Fprint(pw, "ICS...")
|
||||||
|
tcheckf(t, err, "write ics")
|
||||||
|
|
||||||
// Two inline PDFs.
|
// Two inline PDFs.
|
||||||
pw, err := mp.CreateFormFile("inlinefile", "test.pdf")
|
pw, err = mp.CreateFormFile("inlinefile", "test.pdf")
|
||||||
tcheckf(t, err, "create inline pdf file")
|
tcheckf(t, err, "create inline pdf file")
|
||||||
_, err = fmt.Fprint(pw, "%PDF-")
|
_, err = fmt.Fprint(pw, "%PDF-")
|
||||||
tcheckf(t, err, "write pdf")
|
tcheckf(t, err, "write pdf")
|
||||||
|
|
Loading…
Reference in a new issue