1
1
mirror of https://github.com/go-gitea/gitea.git synced 2025-02-14 07:41:21 +01:00

Use new mail package instead of an unmintained one (#32682)

Resolve #18664
This commit is contained in:
Lunny Xiao 2024-12-04 14:33:43 -08:00 committed by GitHub
parent 4142397b0b
commit 5ab7aa700f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 133 additions and 71 deletions

File diff suppressed because one or more lines are too long

3
go.mod

@ -114,6 +114,7 @@ require (
github.com/tstranex/u2f v1.0.0
github.com/ulikunitz/xz v0.5.12
github.com/urfave/cli/v2 v2.27.5
github.com/wneessen/go-mail v0.5.2
github.com/xanzy/go-gitlab v0.112.0
github.com/xeipuuv/gojsonschema v1.2.0
github.com/yohcop/openid-go v1.0.1
@ -130,7 +131,6 @@ require (
golang.org/x/tools v0.26.0
google.golang.org/grpc v1.67.1
google.golang.org/protobuf v1.35.1
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.67.0
gopkg.in/yaml.v3 v3.0.1
mvdan.cc/xurls/v2 v2.5.0
@ -319,7 +319,6 @@ require (
golang.org/x/mod v0.21.0 // indirect
golang.org/x/time v0.7.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

25
go.sum

@ -815,6 +815,8 @@ github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/wneessen/go-mail v0.5.2 h1:MZKwgHJoRboLJ+EHMLuHpZc95wo+u1xViL/4XSswDT8=
github.com/wneessen/go-mail v0.5.2/go.mod h1:kRroJvEq2hOSEPFRiKjN7Csrz0G1w+RpiGR3b6yo+Ck=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xanzy/go-gitlab v0.112.0 h1:6Z0cqEooCvBMfBIHw+CgO4AKGRV8na/9781xOb0+DKw=
@ -887,8 +889,10 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
@ -901,6 +905,9 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -920,8 +927,10 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
@ -934,6 +943,9 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -966,10 +978,13 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@ -977,8 +992,10 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -989,7 +1006,9 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
@ -1004,6 +1023,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -1024,8 +1045,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -1033,8 +1052,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=

@ -93,20 +93,20 @@ func TestComposeIssueCommentMessage(t *testing.T) {
assert.NoError(t, err)
assert.Len(t, msgs, 2)
gomailMsg := msgs[0].ToMessage()
replyTo := gomailMsg.GetHeader("Reply-To")[0]
subject := gomailMsg.GetHeader("Subject")[0]
replyTo := gomailMsg.GetGenHeader("Reply-To")[0]
subject := gomailMsg.GetGenHeader("Subject")[0]
assert.Len(t, gomailMsg.GetHeader("To"), 1, "exactly one recipient is expected in the To field")
assert.Len(t, gomailMsg.GetAddrHeader("To"), 1, "exactly one recipient is expected in the To field")
tokenRegex := regexp.MustCompile(`\Aincoming\+(.+)@localhost\z`)
assert.Regexp(t, tokenRegex, replyTo)
token := tokenRegex.FindAllStringSubmatch(replyTo, 1)[0][1]
assert.Equal(t, "Re: ", subject[:4], "Comment reply subject should contain Re:")
assert.Equal(t, "Re: [user2/repo1] @user2 #1 - issue1", subject)
assert.Equal(t, "<user2/repo1/issues/1@localhost>", gomailMsg.GetHeader("In-Reply-To")[0], "In-Reply-To header doesn't match")
assert.ElementsMatch(t, []string{"<user2/repo1/issues/1@localhost>", "<reply-" + token + "@localhost>"}, gomailMsg.GetHeader("References"), "References header doesn't match")
assert.Equal(t, "<user2/repo1/issues/1/comment/2@localhost>", gomailMsg.GetHeader("Message-ID")[0], "Message-ID header doesn't match")
assert.Equal(t, "<mailto:"+replyTo+">", gomailMsg.GetHeader("List-Post")[0])
assert.Len(t, gomailMsg.GetHeader("List-Unsubscribe"), 2) // url + mailto
assert.Equal(t, "<user2/repo1/issues/1@localhost>", gomailMsg.GetGenHeader("In-Reply-To")[0], "In-Reply-To header doesn't match")
assert.ElementsMatch(t, []string{"<user2/repo1/issues/1@localhost>", "<reply-" + token + "@localhost>"}, gomailMsg.GetGenHeader("References"), "References header doesn't match")
assert.Equal(t, "<user2/repo1/issues/1/comment/2@localhost>", gomailMsg.GetGenHeader("Message-ID")[0], "Message-ID header doesn't match")
assert.Equal(t, "<mailto:"+replyTo+">", gomailMsg.GetGenHeader("List-Post")[0])
assert.Len(t, gomailMsg.GetGenHeader("List-Unsubscribe"), 2) // url + mailto
var buf bytes.Buffer
gomailMsg.WriteTo(&buf)
@ -139,19 +139,19 @@ func TestComposeIssueMessage(t *testing.T) {
assert.Len(t, msgs, 2)
gomailMsg := msgs[0].ToMessage()
mailto := gomailMsg.GetHeader("To")
subject := gomailMsg.GetHeader("Subject")
messageID := gomailMsg.GetHeader("Message-ID")
inReplyTo := gomailMsg.GetHeader("In-Reply-To")
references := gomailMsg.GetHeader("References")
mailto := gomailMsg.GetAddrHeader("To")
subject := gomailMsg.GetGenHeader("Subject")
messageID := gomailMsg.GetGenHeader("Message-ID")
inReplyTo := gomailMsg.GetGenHeader("In-Reply-To")
references := gomailMsg.GetGenHeader("References")
assert.Len(t, mailto, 1, "exactly one recipient is expected in the To field")
assert.Equal(t, "[user2/repo1] @user2 #1 - issue1", subject[0])
assert.Equal(t, "<user2/repo1/issues/1@localhost>", inReplyTo[0], "In-Reply-To header doesn't match")
assert.Equal(t, "<user2/repo1/issues/1@localhost>", references[0], "References header doesn't match")
assert.Equal(t, "<user2/repo1/issues/1@localhost>", messageID[0], "Message-ID header doesn't match")
assert.Empty(t, gomailMsg.GetHeader("List-Post")) // incoming mail feature disabled
assert.Len(t, gomailMsg.GetHeader("List-Unsubscribe"), 1) // url without mailto
assert.Empty(t, gomailMsg.GetGenHeader("List-Post")) // incoming mail feature disabled
assert.Len(t, gomailMsg.GetGenHeader("List-Unsubscribe"), 1) // url without mailto
}
func TestTemplateSelection(t *testing.T) {
@ -169,7 +169,7 @@ func TestTemplateSelection(t *testing.T) {
template.Must(bodyTemplates.New("issue/close").Parse("issue/close/body"))
expect := func(t *testing.T, msg *sender_service.Message, expSubject, expBody string) {
subject := msg.ToMessage().GetHeader("Subject")
subject := msg.ToMessage().GetGenHeader("Subject")
msgbuf := new(bytes.Buffer)
_, _ = msg.ToMessage().WriteTo(msgbuf)
wholemsg := msgbuf.String()
@ -225,7 +225,7 @@ func TestTemplateServices(t *testing.T) {
Content: "test body", Comment: comment,
}, recipients, fromMention, "TestTemplateServices")
subject := msg.ToMessage().GetHeader("Subject")
subject := msg.ToMessage().GetGenHeader("Subject")
msgbuf := new(bytes.Buffer)
_, _ = msg.ToMessage().WriteTo(msgbuf)
wholemsg := msgbuf.String()

@ -48,11 +48,11 @@ func NewContext(ctx context.Context) {
mailQueue = queue.CreateSimpleQueue(graceful.GetManager().ShutdownContext(), "mail", func(items ...*sender_service.Message) []*sender_service.Message {
for _, msg := range items {
gomailMsg := msg.ToMessage()
log.Trace("New e-mail sending request %s: %s", gomailMsg.GetHeader("To"), msg.Info)
log.Trace("New e-mail sending request %s: %s", gomailMsg.GetGenHeader("To"), msg.Info)
if err := sender_service.Send(sender, msg); err != nil {
log.Error("Failed to send emails %s: %s - %v", gomailMsg.GetHeader("To"), msg.Info, err)
log.Error("Failed to send emails %s: %s - %v", gomailMsg.GetGenHeader("To"), msg.Info, err)
} else {
log.Trace("E-mails sent %s: %s", gomailMsg.GetHeader("To"), msg.Info)
log.Trace("E-mails sent %s: %s", gomailMsg.GetGenHeader("To"), msg.Info)
}
}
return nil

@ -0,0 +1,14 @@
// Copyright 2019 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package sender
import (
"testing"
"code.gitea.io/gitea/models/unittest"
)
func TestMain(m *testing.M) {
unittest.MainTest(m)
}

@ -6,6 +6,7 @@ package sender
import (
"fmt"
"hash/fnv"
"net/mail"
"strings"
"time"
@ -14,7 +15,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"github.com/jaytaylor/html2text"
"gopkg.in/gomail.v2"
gomail "github.com/wneessen/go-mail"
)
// Message mail body and log info
@ -31,45 +32,46 @@ type Message struct {
}
// ToMessage converts a Message to gomail.Message
func (m *Message) ToMessage() *gomail.Message {
msg := gomail.NewMessage()
msg.SetAddressHeader("From", m.FromAddress, m.FromDisplayName)
msg.SetHeader("To", m.To)
func (m *Message) ToMessage() *gomail.Msg {
msg := gomail.NewMsg()
addr := mail.Address{Name: m.FromDisplayName, Address: m.FromAddress}
_ = msg.SetAddrHeader("From", addr.String())
_ = msg.SetAddrHeader("To", m.To)
if m.ReplyTo != "" {
msg.SetHeader("Reply-To", m.ReplyTo)
msg.SetGenHeader("Reply-To", m.ReplyTo)
}
for header := range m.Headers {
msg.SetHeader(header, m.Headers[header]...)
msg.SetGenHeader(gomail.Header(header), m.Headers[header]...)
}
if setting.MailService.SubjectPrefix != "" {
msg.SetHeader("Subject", setting.MailService.SubjectPrefix+" "+m.Subject)
msg.SetGenHeader("Subject", setting.MailService.SubjectPrefix+" "+m.Subject)
} else {
msg.SetHeader("Subject", m.Subject)
msg.SetGenHeader("Subject", m.Subject)
}
msg.SetDateHeader("Date", m.Date)
msg.SetHeader("X-Auto-Response-Suppress", "All")
msg.SetDateWithValue(m.Date)
msg.SetGenHeader("X-Auto-Response-Suppress", "All")
plainBody, err := html2text.FromString(m.Body)
if err != nil || setting.MailService.SendAsPlainText {
if strings.Contains(base.TruncateString(m.Body, 100), "<html>") {
log.Warn("Mail contains HTML but configured to send as plain text.")
}
msg.SetBody("text/plain", plainBody)
msg.SetBodyString("text/plain", plainBody)
} else {
msg.SetBody("text/plain", plainBody)
msg.AddAlternative("text/html", m.Body)
msg.SetBodyString("text/plain", plainBody)
msg.AddAlternativeString("text/html", m.Body)
}
if len(msg.GetHeader("Message-ID")) == 0 {
msg.SetHeader("Message-ID", m.generateAutoMessageID())
if len(msg.GetGenHeader("Message-ID")) == 0 {
msg.SetGenHeader("Message-ID", m.generateAutoMessageID())
}
for k, v := range setting.MailService.OverrideHeader {
if len(msg.GetHeader(k)) != 0 {
if len(msg.GetGenHeader(gomail.Header(k))) != 0 {
log.Debug("Mailer override header '%s' as per config", k)
}
msg.SetHeader(k, v...)
msg.SetGenHeader(gomail.Header(k), v...)
}
return msg

@ -25,25 +25,27 @@ func TestGenerateMessageID(t *testing.T) {
m := NewMessageFrom("", "display-name", "from-address", "subject", "body")
m.Date = date
gm := m.ToMessage()
assert.Equal(t, "<autogen-946782245000-41e8fc54a8ad3a3f@localhost>", gm.GetHeader("Message-ID")[0])
assert.Equal(t, "<autogen-946782245000-41e8fc54a8ad3a3f@localhost>", gm.GetGenHeader("Message-ID")[0])
m = NewMessageFrom("a@b.com", "display-name", "from-address", "subject", "body")
m.Date = date
gm = m.ToMessage()
assert.Equal(t, "<autogen-946782245000-cc88ce3cfe9bd04f@localhost>", gm.GetHeader("Message-ID")[0])
assert.Equal(t, "<autogen-946782245000-cc88ce3cfe9bd04f@localhost>", gm.GetGenHeader("Message-ID")[0])
m = NewMessageFrom("a@b.com", "display-name", "from-address", "subject", "body")
m.SetHeader("Message-ID", "<msg-d@domain.com>")
gm = m.ToMessage()
assert.Equal(t, "<msg-d@domain.com>", gm.GetHeader("Message-ID")[0])
assert.Equal(t, "<msg-d@domain.com>", gm.GetGenHeader("Message-ID")[0])
}
func TestToMessage(t *testing.T) {
oldConf := *setting.MailService
oldConf := setting.MailService
defer func() {
setting.MailService = &oldConf
setting.MailService = oldConf
}()
setting.MailService.From = "test@gitea.com"
setting.MailService = &setting.Mailer{
From: "test@gitea.com",
}
m1 := Message{
Info: "info",
@ -54,18 +56,24 @@ func TestToMessage(t *testing.T) {
Body: "Some Issue got closed by Y-Man",
}
assertHeaders := func(t *testing.T, expected, header map[string]string) {
for k, v := range expected {
assert.Equal(t, v, header[k], "Header %s should be %s but got %s", k, v, header[k])
}
}
buf := &strings.Builder{}
_, err := m1.ToMessage().WriteTo(buf)
assert.NoError(t, err)
header, _ := extractMailHeaderAndContent(t, buf.String())
assert.EqualValues(t, map[string]string{
assertHeaders(t, map[string]string{
"Content-Type": "multipart/alternative;",
"Date": "Mon, 01 Jan 0001 00:00:00 +0000",
"From": "\"Test Gitea\" <test@gitea.com>",
"Message-ID": "<autogen--6795364578871-69c000786adc60dc@localhost>",
"Mime-Version": "1.0",
"MIME-Version": "1.0",
"Subject": "Issue X Closed",
"To": "a@b.com",
"To": "<a@b.com>",
"X-Auto-Response-Suppress": "All",
}, header)
@ -78,14 +86,14 @@ func TestToMessage(t *testing.T) {
_, err = m1.ToMessage().WriteTo(buf)
assert.NoError(t, err)
header, _ = extractMailHeaderAndContent(t, buf.String())
assert.EqualValues(t, map[string]string{
assertHeaders(t, map[string]string{
"Content-Type": "multipart/alternative;",
"Date": "Mon, 01 Jan 0001 00:00:00 +0000",
"From": "\"Test Gitea\" <test@gitea.com>",
"Message-ID": "",
"Mime-Version": "1.0",
"MIME-Version": "1.0",
"Subject": "Issue X Closed",
"To": "a@b.com",
"To": "<a@b.com>",
"X-Auto-Response-Suppress": "All",
"Auto-Submitted": "auto-generated",
}, header)

@ -4,13 +4,15 @@
package sender
import (
"io"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"gopkg.in/gomail.v2"
)
type Sender gomail.Sender
type Sender interface {
Send(from string, to []string, msg io.WriterTo) error
}
var Send = send
@ -19,9 +21,18 @@ func send(sender Sender, msgs ...*Message) error {
log.Error("Mailer: Send is being invoked but mail service hasn't been initialized")
return nil
}
goMsgs := []*gomail.Message{}
for _, msg := range msgs {
goMsgs = append(goMsgs, msg.ToMessage())
m := msg.ToMessage()
froms := m.GetFrom()
to, err := m.GetRecipients()
if err != nil {
return err
}
// TODO: implement sending from multiple addresses
if err := sender.Send(froms[0].Address, to, m); err != nil {
return err
}
}
return gomail.Send(sender, goMsgs...)
return nil
}

@ -8,12 +8,13 @@ import (
"fmt"
"io"
"net"
"net/smtp"
"os"
"strings"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/wneessen/go-mail/smtp"
)
// SMTPSender Sender SMTP mail sender
@ -106,7 +107,7 @@ func (s *SMTPSender) Send(from string, to []string, msg io.WriterTo) error {
if strings.Contains(options, "CRAM-MD5") {
auth = smtp.CRAMMD5Auth(opts.User, opts.Passwd)
} else if strings.Contains(options, "PLAIN") {
auth = smtp.PlainAuth("", opts.User, opts.Passwd, host)
auth = smtp.PlainAuth("", opts.User, opts.Passwd, host, false)
} else if strings.Contains(options, "LOGIN") {
// Patch for AUTH LOGIN
auth = LoginAuth(opts.User, opts.Passwd)
@ -146,5 +147,10 @@ func (s *SMTPSender) Send(from string, to []string, msg io.WriterTo) error {
return fmt.Errorf("SMTP close failed: %w", err)
}
return client.Quit()
err = client.Quit()
if err != nil {
log.Error("Quit client failed: %v", err)
}
return nil
}

@ -5,9 +5,9 @@ package sender
import (
"fmt"
"net/smtp"
"github.com/Azure/go-ntlmssp"
"github.com/wneessen/go-mail/smtp"
)
type loginAuth struct {