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,62 @@ 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+ // RawMessage (non-Email) fallback
35+ return self ::normalizeRaw ($ message , $ envelope , $ raw );
36+ }
37+
38+ /** @return array<string,mixed> */
39+ private static function normalizeRaw (
40+ RawMessage $ rawMessage ,
41+ ?Envelope $ envelope ,
42+ ?string $ raw
43+ ): array {
44+ return [
45+ 'version ' => 1 ,
46+ 'saved_at ' => (new \DateTimeImmutable ())->format (\DateTimeInterface::ATOM ),
47+ 'subject ' => null ,
48+ 'from ' => [],
49+ 'to ' => [],
50+ 'cc ' => [],
51+ 'bcc ' => [],
52+ 'reply_to ' => [],
53+ 'text ' => null ,
54+ 'html ' => null ,
55+ 'headers ' => [],
56+ 'attachments ' => [],
57+ 'raw ' => $ rawMessage ,
58+ ];
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+
78+ $ filename = $ part ->getFilename ();
3779 $ contentId = $ part ->getPreparedHeaders ()->has ('Content-ID ' )
3880 ? trim ($ part ->getPreparedHeaders ()->get ('Content-ID ' )->getBodyAsString (), '<> ' )
3981 : null ;
@@ -42,7 +84,6 @@ public static function normalize(
4284 ? $ part ->getPreparedHeaders ()->get ('Content-Disposition ' )->getBodyAsString ()
4385 : null ;
4486
45- $ filename = method_exists ($ part , 'getFilename ' ) ? $ part ->getFilename () : null ;
4687
4788 $ contentType = $ part ->getPreparedHeaders ()->has ('Content-Type ' )
4889 ? $ part ->getPreparedHeaders ()->get ('Content-Type ' )->getBodyAsString ()
@@ -71,7 +112,7 @@ public static function normalize(
71112 'inline ' => $ contentId !== null ,
72113 'size ' => $ size ,
73114 'content ' => $ bodyBase64 , // base64 or null
74- ], static fn ($ v ) => $ v !== null );
115+ ], static fn ($ v ) => $ v !== null );
75116 }
76117
77118 // Prefer explicitly set envelope sender/recipients, fallback to headers
@@ -102,30 +143,27 @@ public static function normalize(
102143
103144 'headers ' => $ headers , // full header map
104145 'attachments ' => $ attachments , // metadata (+ content if enabled)
105- ];
106146
107- if ($ keepRaw && $ raw !== null ) {
108- $ payload ['raw ' ] = $ raw ;
109- }
147+ 'raw ' => $ raw , // raw email source if provided
148+ ];
110149
111150 return $ payload ;
112151 }
113152
114153 /**
115154 * @param Address[] $addresses
155+ *
116156 * @return array<int,array{name?:string,email:string}>
117157 */
118158 private static function addressesToArray (iterable $ addresses ): array
119159 {
120160 $ out = [];
121161 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 ;
162+ $ row = ['email ' => $ addr ->getAddress ()];
163+ if ($ addr ->getName () !== '' ) {
164+ $ row ['name ' ] = $ addr ->getName ();
128165 }
166+ $ out [] = $ row ;
129167 }
130168
131169 return $ out ;
@@ -139,10 +177,11 @@ private static function addressToArray(Address $address): array
139177 ]);
140178 }
141179
180+
142181 private static function firstHeader (Email $ email , string $ name ): ?string
143182 {
144183 $ headers = $ email ->getHeaders ();
145- if (! $ headers ->has ($ name )) {
184+ if (!$ headers ->has ($ name )) {
146185 return null ;
147186 }
148187
0 commit comments