Improvements and tests for eml conversion (#4644)
<!-- PR description--> --- #### Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [x] 🕐 Yes, but in a later PR - [ ] ⛔ No #### Type of change <!--- Please check the type of change your PR introduces: ---> - [ ] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [x] 🤖 Supportability/Tests - [ ] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup #### Issue(s) <!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. --> * https://github.com/alcionai/corso/issues/3893 #### Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
576b8b6370
commit
c3b7246ee9
@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased] (beta)
|
||||
|
||||
### Added
|
||||
- Added export support for emails in exchange backups as `.eml` files
|
||||
|
||||
### Changed
|
||||
- Change file extension of messages export to json to match the content
|
||||
|
||||
|
||||
@ -7,7 +7,6 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/converters/eml"
|
||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -31,12 +30,7 @@ func main() {
|
||||
case "msg":
|
||||
switch to {
|
||||
case "eml":
|
||||
msg, err := api.BytesToMessageable(body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
out, err = eml.ToEml(context.Background(), msg)
|
||||
out, err = eml.FromJSON(context.Background(), body)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@ -13,26 +13,31 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/alcionai/clues"
|
||||
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||
mail "github.com/xhit/go-simple-mail/v2"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/pkg/logger"
|
||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||
)
|
||||
|
||||
const (
|
||||
fromFormat = "%s <%s>"
|
||||
dateFormat = "2006-01-02 15:04:05 MST" // from xhit/go-simple-mail
|
||||
addressFormat = "%s <%s>"
|
||||
dateFormat = "2006-01-02 15:04:05 MST" // from xhit/go-simple-mail
|
||||
)
|
||||
|
||||
// ToEml converts a Messageable to .eml format
|
||||
func ToEml(ctx context.Context, data models.Messageable) (string, error) {
|
||||
// FromJSON converts a Messageable (as json) to .eml format
|
||||
func FromJSON(ctx context.Context, body []byte) (string, error) {
|
||||
data, err := api.BytesToMessageable(body)
|
||||
if err != nil {
|
||||
return "", clues.Wrap(err, "converting to messageble")
|
||||
}
|
||||
|
||||
email := mail.NewMSG()
|
||||
|
||||
if data.GetFrom() != nil {
|
||||
email.SetFrom(
|
||||
fmt.Sprintf(
|
||||
fromFormat,
|
||||
addressFormat,
|
||||
ptr.Val(data.GetFrom().GetEmailAddress().GetName()),
|
||||
ptr.Val(data.GetFrom().GetEmailAddress().GetAddress())))
|
||||
}
|
||||
@ -41,7 +46,7 @@ func ToEml(ctx context.Context, data models.Messageable) (string, error) {
|
||||
for _, recipient := range data.GetToRecipients() {
|
||||
email.AddTo(
|
||||
fmt.Sprintf(
|
||||
fromFormat,
|
||||
addressFormat,
|
||||
ptr.Val(recipient.GetEmailAddress().GetName()),
|
||||
ptr.Val(recipient.GetEmailAddress().GetAddress())))
|
||||
}
|
||||
@ -51,7 +56,7 @@ func ToEml(ctx context.Context, data models.Messageable) (string, error) {
|
||||
for _, recipient := range data.GetCcRecipients() {
|
||||
email.AddCc(
|
||||
fmt.Sprintf(
|
||||
fromFormat,
|
||||
addressFormat,
|
||||
ptr.Val(recipient.GetEmailAddress().GetName()),
|
||||
ptr.Val(recipient.GetEmailAddress().GetAddress())))
|
||||
}
|
||||
@ -61,7 +66,7 @@ func ToEml(ctx context.Context, data models.Messageable) (string, error) {
|
||||
for _, recipient := range data.GetBccRecipients() {
|
||||
email.AddBcc(
|
||||
fmt.Sprintf(
|
||||
fromFormat,
|
||||
addressFormat,
|
||||
ptr.Val(recipient.GetEmailAddress().GetName()),
|
||||
ptr.Val(recipient.GetEmailAddress().GetAddress())))
|
||||
}
|
||||
@ -77,7 +82,7 @@ func ToEml(ctx context.Context, data models.Messageable) (string, error) {
|
||||
} else if len(rts) != 0 {
|
||||
email.SetReplyTo(
|
||||
fmt.Sprintf(
|
||||
fromFormat,
|
||||
addressFormat,
|
||||
ptr.Val(rts[0].GetEmailAddress().GetName()),
|
||||
ptr.Val(rts[0].GetEmailAddress().GetAddress())))
|
||||
}
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
package eml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||
"github.com/alcionai/corso/src/internal/converters/eml/testdata"
|
||||
"github.com/alcionai/corso/src/internal/tester"
|
||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||
@ -26,11 +29,57 @@ func (suite *EMLUnitSuite) TestConvert_messageble_to_eml() {
|
||||
ctx, flush := tester.NewContext(t)
|
||||
defer flush()
|
||||
|
||||
msg, err := api.BytesToMessageable([]byte(testdata.EmailWithAttachments))
|
||||
body := []byte(testdata.EmailWithAttachments)
|
||||
|
||||
out, err := FromJSON(ctx, body)
|
||||
assert.NoError(t, err, "converting to eml")
|
||||
|
||||
msg, err := api.BytesToMessageable(body)
|
||||
require.NoError(t, err, "creating message")
|
||||
|
||||
_, err = ToEml(ctx, msg)
|
||||
// TODO(meain): add more tests on the generated content
|
||||
// Cannot test output directly as it contains a random boundary
|
||||
assert.NoError(t, err, "converting to eml")
|
||||
assert.Contains(t, out, fmt.Sprintf("Subject: %s", ptr.Val(msg.GetSubject())))
|
||||
assert.Contains(t, out, fmt.Sprintf("Date: %s", msg.GetSentDateTime().Format(time.RFC1123Z)))
|
||||
assert.Contains(
|
||||
t,
|
||||
out,
|
||||
fmt.Sprintf(
|
||||
`From: "%s" <%s>`,
|
||||
ptr.Val(msg.GetFrom().GetEmailAddress().GetName()),
|
||||
ptr.Val(msg.GetFrom().GetEmailAddress().GetAddress())))
|
||||
|
||||
for _, addr := range msg.GetToRecipients() {
|
||||
assert.Contains(
|
||||
t,
|
||||
out,
|
||||
fmt.Sprintf(
|
||||
`To: "%s" <%s>`,
|
||||
ptr.Val(addr.GetEmailAddress().GetName()),
|
||||
ptr.Val(addr.GetEmailAddress().GetAddress())))
|
||||
}
|
||||
|
||||
for _, addr := range msg.GetCcRecipients() {
|
||||
assert.Contains(
|
||||
t,
|
||||
out,
|
||||
fmt.Sprintf(
|
||||
`Cc: "%s" <%s>`,
|
||||
ptr.Val(addr.GetEmailAddress().GetName()),
|
||||
ptr.Val(addr.GetEmailAddress().GetAddress())))
|
||||
}
|
||||
|
||||
for _, addr := range msg.GetBccRecipients() {
|
||||
assert.Contains(
|
||||
t,
|
||||
out,
|
||||
fmt.Sprintf(
|
||||
`Bcc: "%s" <%s>`,
|
||||
ptr.Val(addr.GetEmailAddress().GetName()),
|
||||
ptr.Val(addr.GetEmailAddress().GetAddress())))
|
||||
}
|
||||
|
||||
// Only fist 30 chars as the .eml generator can introduce a
|
||||
// newline in between the text to limit the column width of the
|
||||
// output. It does not affect the data, but can break our tests and
|
||||
// so using 30 as a safe limit to test.
|
||||
assert.Contains(t, out, ptr.Val(msg.GetBody().GetContent())[:30], "body")
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@ import (
|
||||
"github.com/alcionai/corso/src/pkg/export"
|
||||
"github.com/alcionai/corso/src/pkg/fault"
|
||||
"github.com/alcionai/corso/src/pkg/path"
|
||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||
)
|
||||
|
||||
func NewExportCollection(
|
||||
@ -65,17 +64,7 @@ func streamItems(
|
||||
continue
|
||||
}
|
||||
|
||||
msg, err := api.BytesToMessageable(content)
|
||||
if err != nil {
|
||||
ch <- export.Item{
|
||||
ID: id,
|
||||
Error: clues.Wrap(err, "parsing email"),
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
email, err := eml.ToEml(ctx, msg)
|
||||
email, err := eml.FromJSON(ctx, content)
|
||||
if err != nil {
|
||||
ch <- export.Item{
|
||||
ID: id,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user