88use Symfony \Component \Mailer \Envelope ;
99use Symfony \Component \Mime \Address ;
1010use Symfony \Component \Mime \Email ;
11+ use Symfony \Component \Mime \Header \Headers ;
1112use Symfony \Component \Mime \Part \DataPart ;
13+ use Symfony \Component \Mime \RawMessage ;
1214
1315final class MessageNormalizer
1416{
@@ -18,22 +20,61 @@ final class MessageNormalizer
1820 *
1921 * @return array<string,mixed>
2022 */
23+ /** @return array<string,mixed> */
2124 public static function normalize (
22- Email $ email ,
25+ Email | RawMessage $ message ,
2326 ?Envelope $ envelope = null ,
2427 ?string $ raw = null ,
2528 bool $ storeAttachmentsInline = false
2629 ): array {
27- $ keepRaw = true ;
30+ if ($ message instanceof Email) {
31+
32+ return self ::normalizeEmail ($ message , $ envelope , $ raw , $ storeAttachmentsInline );
33+ }
34+
35+ // RawMessage (non-Email) fallback
36+ return self ::normalizeRaw ($ message , $ envelope , $ raw );
37+ }
38+
39+ /** @return array<string,mixed> */
40+ private static function normalizeRaw (
41+ RawMessage $ rawMessage ,
42+ ?Envelope $ envelope ,
43+ ?string $ raw
44+ ): array {
45+ return [
46+ 'version ' => 1 ,
47+ 'saved_at ' => (new \DateTimeImmutable )->format (\DateTimeInterface::ATOM ),
48+ 'subject ' => null ,
49+ 'from ' => [],
50+ 'to ' => [],
51+ 'cc ' => [],
52+ 'bcc ' => [],
53+ 'reply_to ' => [],
54+ 'text ' => null ,
55+ 'html ' => null ,
56+ 'headers ' => [],
57+ 'attachments ' => [],
58+ 'raw ' => $ rawMessage ,
59+ ];
60+ }
61+
62+ /** @return array<string,mixed> */
63+ private static function normalizeEmail (
64+ Email $ email ,
65+ ?Envelope $ envelope ,
66+ ?string $ raw ,
67+ bool $ storeAttachmentsInline
68+ ): array {
2869 $ headers = [];
2970 foreach ($ email ->getHeaders ()->all () as $ header ) {
30- // flatten to "Name" => ["value1", "value2"...]
3171 $ headers [$ header ->getName ()][] = trim ($ header ->getBodyAsString ());
3272 }
3373
3474 $ attachments = [];
3575 foreach ($ email ->getAttachments () as $ part ) {
3676 /** @var DataPart $part */
77+ $ filename = $ part ->getFilename ();
3778 $ contentId = $ part ->getPreparedHeaders ()->has ('Content-ID ' )
3879 ? trim ($ part ->getPreparedHeaders ()->get ('Content-ID ' )->getBodyAsString (), '<> ' )
3980 : null ;
@@ -42,8 +83,6 @@ public static function normalize(
4283 ? $ part ->getPreparedHeaders ()->get ('Content-Disposition ' )->getBodyAsString ()
4384 : null ;
4485
45- $ filename = method_exists ($ part , 'getFilename ' ) ? $ part ->getFilename () : null ;
46-
4786 $ contentType = $ part ->getPreparedHeaders ()->has ('Content-Type ' )
4887 ? $ part ->getPreparedHeaders ()->get ('Content-Type ' )->getBodyAsString ()
4988 : null ;
@@ -102,11 +141,9 @@ public static function normalize(
102141
103142 'headers ' => $ headers , // full header map
104143 'attachments ' => $ attachments , // metadata (+ content if enabled)
105- ];
106144
107- if ($ keepRaw && $ raw !== null ) {
108- $ payload ['raw ' ] = $ raw ;
109- }
145+ 'raw ' => $ raw , // raw email source if provided
146+ ];
110147
111148 return $ payload ;
112149 }
@@ -119,13 +156,11 @@ private static function addressesToArray(iterable $addresses): array
119156 {
120157 $ out = [];
121158 foreach ($ addresses as $ addr ) {
122- if ($ addr instanceof Address) {
123- $ row = ['email ' => $ addr ->getAddress ()];
124- if ($ addr ->getName () !== '' ) {
125- $ row ['name ' ] = $ addr ->getName ();
126- }
127- $ out [] = $ row ;
159+ $ row = ['email ' => $ addr ->getAddress ()];
160+ if ($ addr ->getName () !== '' ) {
161+ $ row ['name ' ] = $ addr ->getName ();
128162 }
163+ $ out [] = $ row ;
129164 }
130165
131166 return $ out ;
0 commit comments