mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 17:47:03 +00:00
Merge branch 'feature/to-header' into develop
- Messages now store To information
This commit is contained in:
@@ -7,6 +7,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
[Unreleased]
|
[Unreleased]
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Storage of To: header in messages (likely breaks existing datastores)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- We should no longer run out of file handles when dealing with a large number
|
- We should no longer run out of file handles when dealing with a large number
|
||||||
of recipients on a single message.
|
of recipients on a single message.
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ main() {
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
# Use jq to pretty-print if installed and we are expecting JSON output
|
# Use jq to pretty-print if installed and we are expecting JSON output
|
||||||
if [ $pretty ] && [ $is_json ] && type -P jq; then
|
if [ $pretty ] && [ $is_json ] && type -P jq >/dev/null; then
|
||||||
curl -s $curl_opts -H "Accept: application/json" --noproxy "$API_HOST" -X "$method" "$url" | jq .
|
curl -s $curl_opts -H "Accept: application/json" --noproxy "$API_HOST" -X "$method" "$url" | jq .
|
||||||
else
|
else
|
||||||
curl -s $curl_opts -H "Accept: application/json" --noproxy "$API_HOST" -X "$method" "$url"
|
curl -s $curl_opts -H "Accept: application/json" --noproxy "$API_HOST" -X "$method" "$url"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type JSONMessageHeaderV1 struct {
|
|||||||
Mailbox string `json:"mailbox"`
|
Mailbox string `json:"mailbox"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
|
To []string `json:"to"`
|
||||||
Subject string `json:"subject"`
|
Subject string `json:"subject"`
|
||||||
Date time.Time `json:"date"`
|
Date time.Time `json:"date"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
@@ -27,6 +28,7 @@ type JSONMessageV1 struct {
|
|||||||
Mailbox string `json:"mailbox"`
|
Mailbox string `json:"mailbox"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
From string `json:"from"`
|
From string `json:"from"`
|
||||||
|
To []string `json:"to"`
|
||||||
Subject string `json:"subject"`
|
Subject string `json:"subject"`
|
||||||
Date time.Time `json:"date"`
|
Date time.Time `json:"date"`
|
||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
@@ -65,6 +67,7 @@ func MailboxListV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context)
|
|||||||
Mailbox: name,
|
Mailbox: name,
|
||||||
ID: msg.ID(),
|
ID: msg.ID(),
|
||||||
From: msg.From(),
|
From: msg.From(),
|
||||||
|
To: msg.To(),
|
||||||
Subject: msg.Subject(),
|
Subject: msg.Subject(),
|
||||||
Date: msg.Date(),
|
Date: msg.Date(),
|
||||||
Size: msg.Size(),
|
Size: msg.Size(),
|
||||||
@@ -109,6 +112,7 @@ func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *httpd.Context)
|
|||||||
Mailbox: name,
|
Mailbox: name,
|
||||||
ID: msg.ID(),
|
ID: msg.ID(),
|
||||||
From: msg.From(),
|
From: msg.From(),
|
||||||
|
To: msg.To(),
|
||||||
Subject: msg.Subject(),
|
Subject: msg.Subject(),
|
||||||
Date: msg.Date(),
|
Date: msg.Date(),
|
||||||
Size: msg.Size(),
|
Size: msg.Size(),
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const (
|
|||||||
mailboxKey = "mailbox"
|
mailboxKey = "mailbox"
|
||||||
idKey = "id"
|
idKey = "id"
|
||||||
fromKey = "from"
|
fromKey = "from"
|
||||||
|
toKey = "to"
|
||||||
subjectKey = "subject"
|
subjectKey = "subject"
|
||||||
dateKey = "date"
|
dateKey = "date"
|
||||||
sizeKey = "size"
|
sizeKey = "size"
|
||||||
@@ -94,6 +95,7 @@ func TestRestMailboxList(t *testing.T) {
|
|||||||
Mailbox: "good",
|
Mailbox: "good",
|
||||||
ID: "0001",
|
ID: "0001",
|
||||||
From: "from1",
|
From: "from1",
|
||||||
|
To: []string{"to1"},
|
||||||
Subject: "subject 1",
|
Subject: "subject 1",
|
||||||
Date: time.Date(2012, 2, 1, 10, 11, 12, 253, time.FixedZone("PST", -800)),
|
Date: time.Date(2012, 2, 1, 10, 11, 12, 253, time.FixedZone("PST", -800)),
|
||||||
}
|
}
|
||||||
@@ -101,6 +103,7 @@ func TestRestMailboxList(t *testing.T) {
|
|||||||
Mailbox: "good",
|
Mailbox: "good",
|
||||||
ID: "0002",
|
ID: "0002",
|
||||||
From: "from2",
|
From: "from2",
|
||||||
|
To: []string{"to1"},
|
||||||
Subject: "subject 2",
|
Subject: "subject 2",
|
||||||
Date: time.Date(2012, 7, 1, 10, 11, 12, 253, time.FixedZone("PDT", -700)),
|
Date: time.Date(2012, 7, 1, 10, 11, 12, 253, time.FixedZone("PDT", -700)),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ func (m *MockMessage) From() string {
|
|||||||
return args.String(0)
|
return args.String(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockMessage) To() []string {
|
||||||
|
args := m.Called()
|
||||||
|
return args.Get(0).([]string)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MockMessage) Date() time.Time {
|
func (m *MockMessage) Date() time.Time {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).(time.Time)
|
return args.Get(0).(time.Time)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
|
|
||||||
type InputMessageData struct {
|
type InputMessageData struct {
|
||||||
Mailbox, ID, From, Subject string
|
Mailbox, ID, From, Subject string
|
||||||
|
To []string
|
||||||
Date time.Time
|
Date time.Time
|
||||||
Size int
|
Size int
|
||||||
Header mail.Header
|
Header mail.Header
|
||||||
@@ -27,6 +28,7 @@ func (d *InputMessageData) MockMessage() *MockMessage {
|
|||||||
msg := &MockMessage{}
|
msg := &MockMessage{}
|
||||||
msg.On("ID").Return(d.ID)
|
msg.On("ID").Return(d.ID)
|
||||||
msg.On("From").Return(d.From)
|
msg.On("From").Return(d.From)
|
||||||
|
msg.On("To").Return(d.To)
|
||||||
msg.On("Subject").Return(d.Subject)
|
msg.On("Subject").Return(d.Subject)
|
||||||
msg.On("Date").Return(d.Date)
|
msg.On("Date").Return(d.Date)
|
||||||
msg.On("Size").Return(d.Size)
|
msg.On("Size").Return(d.Size)
|
||||||
@@ -79,6 +81,11 @@ func (d *InputMessageData) CompareToJSONHeaderMap(json interface{}) (errors []st
|
|||||||
if msg, ok := isJSONStringEqual(fromKey, d.From, m[fromKey]); !ok {
|
if msg, ok := isJSONStringEqual(fromKey, d.From, m[fromKey]); !ok {
|
||||||
errors = append(errors, msg)
|
errors = append(errors, msg)
|
||||||
}
|
}
|
||||||
|
for i, inputTo := range d.To {
|
||||||
|
if msg, ok := isJSONStringEqual(toKey, inputTo, m[toKey].([]interface{})[i]); !ok {
|
||||||
|
errors = append(errors, msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
if msg, ok := isJSONStringEqual(subjectKey, d.Subject, m[subjectKey]); !ok {
|
if msg, ok := isJSONStringEqual(subjectKey, d.Subject, m[subjectKey]); !ok {
|
||||||
errors = append(errors, msg)
|
errors = append(errors, msg)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ type Mailbox interface {
|
|||||||
type Message interface {
|
type Message interface {
|
||||||
ID() string
|
ID() string
|
||||||
From() string
|
From() string
|
||||||
|
To() []string
|
||||||
Date() time.Time
|
Date() time.Time
|
||||||
Subject() string
|
Subject() string
|
||||||
RawReader() (reader io.ReadCloser, err error)
|
RawReader() (reader io.ReadCloser, err error)
|
||||||
|
|||||||
@@ -295,6 +295,7 @@ type FileMessage struct {
|
|||||||
Fid string
|
Fid string
|
||||||
Fdate time.Time
|
Fdate time.Time
|
||||||
Ffrom string
|
Ffrom string
|
||||||
|
Fto []string
|
||||||
Fsubject string
|
Fsubject string
|
||||||
Fsize int64
|
Fsize int64
|
||||||
// These are for creating new messages only
|
// These are for creating new messages only
|
||||||
@@ -343,6 +344,11 @@ func (m *FileMessage) From() string {
|
|||||||
return m.Ffrom
|
return m.Ffrom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From returns the value of the Message To header
|
||||||
|
func (m *FileMessage) To() []string {
|
||||||
|
return m.Fto
|
||||||
|
}
|
||||||
|
|
||||||
// Subject returns the value of the Message Subject header
|
// Subject returns the value of the Message Subject header
|
||||||
func (m *FileMessage) Subject() string {
|
func (m *FileMessage) Subject() string {
|
||||||
return m.Fsubject
|
return m.Fsubject
|
||||||
@@ -484,10 +490,24 @@ func (m *FileMessage) Close() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only public fields are stored in gob
|
// Only public fields are stored in gob, hence starting with capital F
|
||||||
m.Ffrom = body.GetHeader("From")
|
// Parse From address
|
||||||
|
if address, err := mail.ParseAddress(body.GetHeader("From")); err == nil {
|
||||||
|
m.Ffrom = address.String()
|
||||||
|
} else {
|
||||||
|
m.Ffrom = body.GetHeader("From")
|
||||||
|
}
|
||||||
m.Fsubject = body.GetHeader("Subject")
|
m.Fsubject = body.GetHeader("Subject")
|
||||||
|
|
||||||
|
// Turn the To header into a slice
|
||||||
|
if addresses, err := body.AddressList("To"); err == nil {
|
||||||
|
for _, a := range addresses {
|
||||||
|
m.Fto = append(m.Fto, a.String())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m.Fto = []string{body.GetHeader("To")}
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh the index before adding our message
|
// Refresh the index before adding our message
|
||||||
err = m.mailbox.readIndex()
|
err = m.mailbox.readIndex()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -126,6 +126,11 @@ func (m *MockMessage) From() string {
|
|||||||
return args.String(0)
|
return args.String(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockMessage) To() []string {
|
||||||
|
args := m.Called()
|
||||||
|
return args.Get(0).([]string)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MockMessage) Date() time.Time {
|
func (m *MockMessage) Date() time.Time {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).(time.Time)
|
return args.Get(0).(time.Time)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
# description: Generate test emails for Inbucket
|
# description: Generate test emails for Inbucket
|
||||||
|
|
||||||
set -eo pipefail
|
set -eo pipefail
|
||||||
|
[ $TRACE ] && set -x
|
||||||
|
|
||||||
# We need to be in swaks-tests directory
|
# We need to be in swaks-tests directory
|
||||||
cmdpath="$(dirname "$0")"
|
cmdpath="$(dirname "$0")"
|
||||||
@@ -19,6 +20,7 @@ case "$1" in
|
|||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
to="$1"
|
to="$1"
|
||||||
|
shift
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -28,6 +30,10 @@ export SWAKS_OPT_to="$to@inbucket.local"
|
|||||||
# Basic test
|
# Basic test
|
||||||
swaks $* --h-Subject: "Swaks Plain Text" --body text.txt
|
swaks $* --h-Subject: "Swaks Plain Text" --body text.txt
|
||||||
|
|
||||||
|
# Multi-recipient test
|
||||||
|
swaks $* --to="$to@inbucket.local,Alt User <alternate@inbucket.local>" --h-Subject: "Swaks Multi-Recipient" \
|
||||||
|
--body text.txt
|
||||||
|
|
||||||
# HTML test
|
# HTML test
|
||||||
swaks $* --h-Subject: "Swaks HTML" --data mime-html.raw
|
swaks $* --h-Subject: "Swaks HTML" --data mime-html.raw
|
||||||
|
|
||||||
@@ -35,7 +41,8 @@ swaks $* --h-Subject: "Swaks HTML" --data mime-html.raw
|
|||||||
swaks $* --h-Subject: "Swaks Top Level HTML" --data nonmime-html.raw
|
swaks $* --h-Subject: "Swaks Top Level HTML" --data nonmime-html.raw
|
||||||
|
|
||||||
# Attachment test
|
# Attachment test
|
||||||
swaks $* --h-Subject: "Swaks Attachment" --attach-type image/png --attach favicon.png --body text.txt
|
swaks $* --h-Subject: "Swaks Attachment" --attach-type image/png --attach favicon.png \
|
||||||
|
--body text.txt
|
||||||
|
|
||||||
# Encoded subject line test
|
# Encoded subject line test
|
||||||
swaks $* --data utf8-subject.raw
|
swaks $* --data utf8-subject.raw
|
||||||
|
|||||||
@@ -52,6 +52,13 @@
|
|||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>From:</dt>
|
<dt>From:</dt>
|
||||||
<dd>{{.message.From}}</dd>
|
<dd>{{.message.From}}</dd>
|
||||||
|
<dt>To:</dt>
|
||||||
|
<dd>
|
||||||
|
{{range $i, $addr := .message.To}}
|
||||||
|
{{- if $i}},{{end}}
|
||||||
|
{{$addr -}}
|
||||||
|
{{end}}
|
||||||
|
</dd>
|
||||||
<dt>Date:</dt>
|
<dt>Date:</dt>
|
||||||
<dd>{{.message.Date}}</dd>
|
<dd>{{.message.Date}}</dd>
|
||||||
<dt>Subject:</dt>
|
<dt>Subject:</dt>
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ $(document).ready(function() {
|
|||||||
<script type="text/html" id="list-entry-template">
|
<script type="text/html" id="list-entry-template">
|
||||||
<button data-id="id" type="button" class="message-list-entry list-group-item">
|
<button data-id="id" type="button" class="message-list-entry list-group-item">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-4 col-md-12 text-primary" data-content="subject"
|
<div class="col-sm-4 col-md-12 text-primary" data-content-text="subject"
|
||||||
data-format="subject"/>
|
data-format="subject"/>
|
||||||
<div class="col-sm-4 col-md-12 small" data-content="from"/>
|
<div class="col-sm-4 col-md-12 small" data-content-text="from"/>
|
||||||
<div class="col-sm-4 col-md-12 small" data-content="date" data-format="date"/>
|
<div class="col-sm-4 col-md-12 small" data-content="date" data-format="date"/>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
@@ -34,8 +34,8 @@ $(document).ready(function() {
|
|||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="message-search"
|
<input id="message-search"
|
||||||
type="search"
|
type="search"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
placeholder="search"
|
placeholder="search"
|
||||||
data-toggle="tooltip"
|
data-toggle="tooltip"
|
||||||
data-placement="top"
|
data-placement="top"
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
<th>From:</th>
|
<th>From:</th>
|
||||||
<td>{{.message.From}}</td>
|
<td>{{.message.From}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>To:</th>
|
||||||
|
<td>{{.message.To}}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Date:</th>
|
<th>Date:</th>
|
||||||
<td>{{.message.Date}}</td>
|
<td>{{.message.Date}}</td>
|
||||||
|
|||||||
@@ -478,6 +478,11 @@ func (m *MockMessage) From() string {
|
|||||||
return args.String(0)
|
return args.String(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MockMessage) To() []string {
|
||||||
|
args := m.Called()
|
||||||
|
return args.Get(0).([]string)
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MockMessage) Date() time.Time {
|
func (m *MockMessage) Date() time.Time {
|
||||||
args := m.Called()
|
args := m.Called()
|
||||||
return args.Get(0).(time.Time)
|
return args.Get(0).(time.Time)
|
||||||
|
|||||||
Reference in New Issue
Block a user