@@ -109,13 +109,26 @@ func formatValue(s string) string {
109109 }
110110
111111 if shouldQuote {
112- // None of involved specs specify how to handle " in quoted strings
113- // so we just drop them and hope they are not criticial.
114- return `"` + strings .Replace (s , `"` , `` , - 1 ) + `"`
112+ return `"` + strings .Replace (s , `"` , `\"` , - 1 ) + `"`
115113 }
116114 return s
117115}
118116
117+ var addressOk = map [rune ]struct {}{
118+ // Most ASCII punctuation except for:
119+ // ( ) = "
120+ // as these can cause issues due to ambiguous ABNF rules.
121+ // I.e. technically mentioned characters can be left unquoted, but they can
122+ // be interpreted as parts of non-quoted parameters or comments so it is
123+ // better to quote them.
124+ '#' : {}, '$' : {}, '%' : {}, '&' : {},
125+ '\'' : {}, '*' : {}, '+' : {}, ',' : {},
126+ '.' : {}, '/' : {}, '-' : {}, '@' : {},
127+ '[' : {}, ']' : {}, '\\' : {}, '^' : {},
128+ '_' : {}, '`' : {}, '{' : {}, '|' : {},
129+ '}' : {}, '~' : {},
130+ }
131+
119132func formatPvalue (s string ) string {
120133 // pvalue = [CFWS] ( value / [ [ local-part ] "@" ] domain-name )
121134 // [CFWS]
@@ -129,7 +142,7 @@ func formatPvalue(s string) string {
129142 // for others.
130143 addressLike := true
131144 for _ , ch := range s {
132- if ! unicode .IsLetter (ch ) && ! unicode .IsDigit (ch ) || ch != '@' {
145+ if _ , ok := addressOk [ ch ]; ! unicode .IsLetter (ch ) && ! unicode .IsDigit (ch ) && ! ok {
133146 addressLike = false
134147 }
135148 }
0 commit comments