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)
|
## [Unreleased] (beta)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Added export support for emails in exchange backups as `.eml` files
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Change file extension of messages export to json to match the content
|
- Change file extension of messages export to json to match the content
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/alcionai/corso/src/internal/converters/eml"
|
"github.com/alcionai/corso/src/internal/converters/eml"
|
||||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -31,12 +30,7 @@ func main() {
|
|||||||
case "msg":
|
case "msg":
|
||||||
switch to {
|
switch to {
|
||||||
case "eml":
|
case "eml":
|
||||||
msg, err := api.BytesToMessageable(body)
|
out, err = eml.FromJSON(context.Background(), body)
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
out, err = eml.ToEml(context.Background(), msg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,26 +13,31 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
|
||||||
mail "github.com/xhit/go-simple-mail/v2"
|
mail "github.com/xhit/go-simple-mail/v2"
|
||||||
|
|
||||||
"github.com/alcionai/corso/src/internal/common/ptr"
|
"github.com/alcionai/corso/src/internal/common/ptr"
|
||||||
"github.com/alcionai/corso/src/pkg/logger"
|
"github.com/alcionai/corso/src/pkg/logger"
|
||||||
|
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fromFormat = "%s <%s>"
|
addressFormat = "%s <%s>"
|
||||||
dateFormat = "2006-01-02 15:04:05 MST" // from xhit/go-simple-mail
|
dateFormat = "2006-01-02 15:04:05 MST" // from xhit/go-simple-mail
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToEml converts a Messageable to .eml format
|
// FromJSON converts a Messageable (as json) to .eml format
|
||||||
func ToEml(ctx context.Context, data models.Messageable) (string, error) {
|
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()
|
email := mail.NewMSG()
|
||||||
|
|
||||||
if data.GetFrom() != nil {
|
if data.GetFrom() != nil {
|
||||||
email.SetFrom(
|
email.SetFrom(
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
fromFormat,
|
addressFormat,
|
||||||
ptr.Val(data.GetFrom().GetEmailAddress().GetName()),
|
ptr.Val(data.GetFrom().GetEmailAddress().GetName()),
|
||||||
ptr.Val(data.GetFrom().GetEmailAddress().GetAddress())))
|
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() {
|
for _, recipient := range data.GetToRecipients() {
|
||||||
email.AddTo(
|
email.AddTo(
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
fromFormat,
|
addressFormat,
|
||||||
ptr.Val(recipient.GetEmailAddress().GetName()),
|
ptr.Val(recipient.GetEmailAddress().GetName()),
|
||||||
ptr.Val(recipient.GetEmailAddress().GetAddress())))
|
ptr.Val(recipient.GetEmailAddress().GetAddress())))
|
||||||
}
|
}
|
||||||
@ -51,7 +56,7 @@ func ToEml(ctx context.Context, data models.Messageable) (string, error) {
|
|||||||
for _, recipient := range data.GetCcRecipients() {
|
for _, recipient := range data.GetCcRecipients() {
|
||||||
email.AddCc(
|
email.AddCc(
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
fromFormat,
|
addressFormat,
|
||||||
ptr.Val(recipient.GetEmailAddress().GetName()),
|
ptr.Val(recipient.GetEmailAddress().GetName()),
|
||||||
ptr.Val(recipient.GetEmailAddress().GetAddress())))
|
ptr.Val(recipient.GetEmailAddress().GetAddress())))
|
||||||
}
|
}
|
||||||
@ -61,7 +66,7 @@ func ToEml(ctx context.Context, data models.Messageable) (string, error) {
|
|||||||
for _, recipient := range data.GetBccRecipients() {
|
for _, recipient := range data.GetBccRecipients() {
|
||||||
email.AddBcc(
|
email.AddBcc(
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
fromFormat,
|
addressFormat,
|
||||||
ptr.Val(recipient.GetEmailAddress().GetName()),
|
ptr.Val(recipient.GetEmailAddress().GetName()),
|
||||||
ptr.Val(recipient.GetEmailAddress().GetAddress())))
|
ptr.Val(recipient.GetEmailAddress().GetAddress())))
|
||||||
}
|
}
|
||||||
@ -77,7 +82,7 @@ func ToEml(ctx context.Context, data models.Messageable) (string, error) {
|
|||||||
} else if len(rts) != 0 {
|
} else if len(rts) != 0 {
|
||||||
email.SetReplyTo(
|
email.SetReplyTo(
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
fromFormat,
|
addressFormat,
|
||||||
ptr.Val(rts[0].GetEmailAddress().GetName()),
|
ptr.Val(rts[0].GetEmailAddress().GetName()),
|
||||||
ptr.Val(rts[0].GetEmailAddress().GetAddress())))
|
ptr.Val(rts[0].GetEmailAddress().GetAddress())))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
package eml
|
package eml
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"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/converters/eml/testdata"
|
||||||
"github.com/alcionai/corso/src/internal/tester"
|
"github.com/alcionai/corso/src/internal/tester"
|
||||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
"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)
|
ctx, flush := tester.NewContext(t)
|
||||||
defer flush()
|
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")
|
require.NoError(t, err, "creating message")
|
||||||
|
|
||||||
_, err = ToEml(ctx, msg)
|
assert.Contains(t, out, fmt.Sprintf("Subject: %s", ptr.Val(msg.GetSubject())))
|
||||||
// TODO(meain): add more tests on the generated content
|
assert.Contains(t, out, fmt.Sprintf("Date: %s", msg.GetSentDateTime().Format(time.RFC1123Z)))
|
||||||
// Cannot test output directly as it contains a random boundary
|
assert.Contains(
|
||||||
assert.NoError(t, err, "converting to eml")
|
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/export"
|
||||||
"github.com/alcionai/corso/src/pkg/fault"
|
"github.com/alcionai/corso/src/pkg/fault"
|
||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
"github.com/alcionai/corso/src/pkg/services/m365/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewExportCollection(
|
func NewExportCollection(
|
||||||
@ -65,17 +64,7 @@ func streamItems(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
msg, err := api.BytesToMessageable(content)
|
email, err := eml.FromJSON(ctx, content)
|
||||||
if err != nil {
|
|
||||||
ch <- export.Item{
|
|
||||||
ID: id,
|
|
||||||
Error: clues.Wrap(err, "parsing email"),
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
email, err := eml.ToEml(ctx, msg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ch <- export.Item{
|
ch <- export.Item{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user