1Message Headers 2=============== 3 4Sometimes you'll want to add your own headers to a message or modify/remove 5headers that are already present. You work with the message's HeaderSet to do 6this. 7 8Header Basics 9------------- 10 11All MIME entities in Swift Mailer -- including the message itself -- store 12their headers in a single object called a HeaderSet. This HeaderSet is 13retrieved with the ``getHeaders()`` method. 14 15As mentioned in the previous chapter, everything that forms a part of a message 16in Swift Mailer is a MIME entity that is represented by an instance of 17``Swift_Mime_SimpleMimeEntity``. This includes -- most notably -- the message 18object itself, attachments, MIME parts and embedded images. Each of these MIME 19entities consists of a body and a set of headers that describe the body. 20 21For all of the "standard" headers in these MIME entities, such as the 22``Content-Type``, there are named methods for working with them, such as 23``setContentType()`` and ``getContentType()``. This is because headers are a 24moderately complex area of the library. Each header has a slightly different 25required structure that it must meet in order to comply with the standards that 26govern email (and that are checked by spam blockers etc). 27 28You fetch the HeaderSet from a MIME entity like so:: 29 30 $message = new Swift_Message(); 31 32 // Fetch the HeaderSet from a Message object 33 $headers = $message->getHeaders(); 34 35 $attachment = Swift_Attachment::fromPath('document.pdf'); 36 37 // Fetch the HeaderSet from an attachment object 38 $headers = $attachment->getHeaders(); 39 40The job of the HeaderSet is to contain and manage instances of Header objects. 41Depending upon the MIME entity the HeaderSet came from, the contents of the 42HeaderSet will be different, since an attachment for example has a different 43set of headers to those in a message. 44 45You can find out what the HeaderSet contains with a quick loop, dumping out the 46names of the headers:: 47 48 foreach ($headers->getAll() as $header) { 49 printf("%s<br />\n", $header->getFieldName()); 50 } 51 52 /* 53 Content-Transfer-Encoding 54 Content-Type 55 MIME-Version 56 Date 57 Message-ID 58 From 59 Subject 60 To 61 */ 62 63You can also dump out the rendered HeaderSet by calling its ``toString()`` 64method:: 65 66 echo $headers->toString(); 67 68 /* 69 Message-ID: <1234869991.499a9ee7f1d5e@swift.generated> 70 Date: Tue, 17 Feb 2009 22:26:31 +1100 71 Subject: Awesome subject! 72 From: sender@example.org 73 To: recipient@example.org 74 MIME-Version: 1.0 75 Content-Type: text/plain; charset=utf-8 76 Content-Transfer-Encoding: quoted-printable 77 */ 78 79Where the complexity comes in is when you want to modify an existing header. 80This complexity comes from the fact that each header can be of a slightly 81different type (such as a Date header, or a header that contains email 82addresses, or a header that has key-value parameters on it!). Each header in 83the HeaderSet is an instance of ``Swift_Mime_Header``. They all have common 84functionality, but knowing exactly what type of header you're working with will 85allow you a little more control. 86 87You can determine the type of header by comparing the return value of its 88``getFieldType()`` method with the constants ``TYPE_TEXT``, 89``TYPE_PARAMETERIZED``, ``TYPE_DATE``, ``TYPE_MAILBOX``, ``TYPE_ID`` and 90``TYPE_PATH`` which are defined in ``Swift_Mime_Header``:: 91 92 foreach ($headers->getAll() as $header) { 93 switch ($header->getFieldType()) { 94 case Swift_Mime_Header::TYPE_TEXT: $type = 'text'; 95 break; 96 case Swift_Mime_Header::TYPE_PARAMETERIZED: $type = 'parameterized'; 97 break; 98 case Swift_Mime_Header::TYPE_MAILBOX: $type = 'mailbox'; 99 break; 100 case Swift_Mime_Header::TYPE_DATE: $type = 'date'; 101 break; 102 case Swift_Mime_Header::TYPE_ID: $type = 'ID'; 103 break; 104 case Swift_Mime_Header::TYPE_PATH: $type = 'path'; 105 break; 106 } 107 printf("%s: is a %s header<br />\n", $header->getFieldName(), $type); 108 } 109 110 /* 111 Content-Transfer-Encoding: is a text header 112 Content-Type: is a parameterized header 113 MIME-Version: is a text header 114 Date: is a date header 115 Message-ID: is a ID header 116 From: is a mailbox header 117 Subject: is a text header 118 To: is a mailbox header 119 */ 120 121Headers can be removed from the set, modified within the set, or added to the 122set. 123 124The following sections show you how to work with the HeaderSet and explain the 125details of each implementation of ``Swift_Mime_Header`` that may exist within 126the HeaderSet. 127 128Header Types 129------------ 130 131Because all headers are modeled on different data (dates, addresses, text!) 132there are different types of Header in Swift Mailer. Swift Mailer attempts to 133categorize all possible MIME headers into more general groups, defined by a 134small number of classes. 135 136Text Headers 137~~~~~~~~~~~~ 138 139Text headers are the simplest type of Header. They contain textual information 140with no special information included within it -- for example the Subject 141header in a message. 142 143There's nothing particularly interesting about a text header, though it is 144probably the one you'd opt to use if you need to add a custom header to a 145message. It represents text just like you'd think it does. If the text contains 146characters that are not permitted in a message header (such as new lines, or 147non-ascii characters) then the header takes care of encoding the text so that 148it can be used. 149 150No header -- including text headers -- in Swift Mailer is vulnerable to 151header-injection attacks. Swift Mailer breaks any attempt at header injection 152by encoding the dangerous data into a non-dangerous form. 153 154It's easy to add a new text header to a HeaderSet. You do this by calling the 155HeaderSet's ``addTextHeader()`` method:: 156 157 $message = new Swift_Message(); 158 $headers = $message->getHeaders(); 159 $headers->addTextHeader('Your-Header-Name', 'the header value'); 160 161Changing the value of an existing text header is done by calling it's 162``setValue()`` method:: 163 164 $subject = $message->getHeaders()->get('Subject'); 165 $subject->setValue('new subject'); 166 167When output via ``toString()``, a text header produces something like the 168following:: 169 170 $subject = $message->getHeaders()->get('Subject'); 171 $subject->setValue('amazing subject line'); 172 echo $subject->toString(); 173 174 /* 175 176 Subject: amazing subject line 177 178 */ 179 180If the header contains any characters that are outside of the US-ASCII range 181however, they will be encoded. This is nothing to be concerned about since mail 182clients will decode them back:: 183 184 $subject = $message->getHeaders()->get('Subject'); 185 $subject->setValue('contains – dash'); 186 echo $subject->toString(); 187 188 /* 189 190 Subject: contains =?utf-8?Q?=E2=80=93?= dash 191 192 */ 193 194Parameterized Headers 195~~~~~~~~~~~~~~~~~~~~~ 196 197Parameterized headers are text headers that contain key-value parameters 198following the textual content. The Content-Type header of a message is a 199parameterized header since it contains charset information after the content 200type. 201 202The parameterized header type is a special type of text header. It extends the 203text header by allowing additional information to follow it. All of the methods 204from text headers are available in addition to the methods described here. 205 206Adding a parameterized header to a HeaderSet is done by using the 207``addParameterizedHeader()`` method which takes a text value like 208``addTextHeader()`` but it also accepts an associative array of key-value 209parameters:: 210 211 $message = new Swift_Message(); 212 $headers = $message->getHeaders(); 213 $headers->addParameterizedHeader( 214 'Header-Name', 'header value', 215 ['foo' => 'bar'] 216 ); 217 218To change the text value of the header, call it's ``setValue()`` method just as 219you do with text headers. 220 221To change the parameters in the header, call the header's ``setParameters()`` 222method or the ``setParameter()`` method (note the pluralization):: 223 224 $type = $message->getHeaders()->get('Content-Type'); 225 226 // setParameters() takes an associative array 227 $type->setParameters([ 228 'name' => 'file.txt', 229 'charset' => 'iso-8859-1' 230 ]); 231 232 // setParameter() takes two args for $key and $value 233 $type->setParameter('charset', 'iso-8859-1'); 234 235When output via ``toString()``, a parameterized header produces something like 236the following:: 237 238 $type = $message->getHeaders()->get('Content-Type'); 239 $type->setValue('text/html'); 240 $type->setParameter('charset', 'utf-8'); 241 242 echo $type->toString(); 243 244 /* 245 246 Content-Type: text/html; charset=utf-8 247 248 */ 249 250If the header contains any characters that are outside of the US-ASCII range 251however, they will be encoded, just like they are for text headers. This is 252nothing to be concerned about since mail clients will decode them back. 253Likewise, if the parameters contain any non-ascii characters they will be 254encoded so that they can be transmitted safely:: 255 256 $attachment = new Swift_Attachment(); 257 $disp = $attachment->getHeaders()->get('Content-Disposition'); 258 $disp->setValue('attachment'); 259 $disp->setParameter('filename', 'report–may.pdf'); 260 echo $disp->toString(); 261 262 /* 263 264 Content-Disposition: attachment; filename*=utf-8''report%E2%80%93may.pdf 265 266 */ 267 268Date Headers 269~~~~~~~~~~~~ 270 271Date headers contains an RFC 2822 formatted date (i.e. what PHP's ``date('r')`` 272returns). They are used anywhere a date or time is needed to be presented as a 273message header. 274 275The data on which a date header is modeled as a DateTimeImmutable object. The 276object is used to create a correctly structured RFC 2822 formatted date with 277timezone such as ``Tue, 17 Feb 2009 22:26:31 +1100``. 278 279The obvious place this header type is used is in the ``Date:`` header of the 280message itself. 281 282It's easy to add a new date header to a HeaderSet. You do this by calling the 283HeaderSet's ``addDateHeader()`` method:: 284 285 $message = new Swift_Message(); 286 $headers = $message->getHeaders(); 287 $headers->addDateHeader('Your-Header', new DateTimeImmutable('3 days ago')); 288 289Changing the value of an existing date header is done by calling it's 290``setDateTime()`` method:: 291 292 $date = $message->getHeaders()->get('Date'); 293 $date->setDateTime(new DateTimeImmutable()); 294 295When output via ``toString()``, a date header produces something like the 296following:: 297 298 $date = $message->getHeaders()->get('Date'); 299 echo $date->toString(); 300 301 /* 302 303 Date: Wed, 18 Feb 2009 13:35:02 +1100 304 305 */ 306 307Mailbox (e-mail address) Headers 308~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 309 310Mailbox headers contain one or more email addresses, possibly with personalized 311names attached to them. The data on which they are modeled is represented by an 312associative array of email addresses and names. 313 314Mailbox headers are probably the most complex header type to understand in 315Swift Mailer because they accept their input as an array which can take various 316forms, as described in the previous chapter. 317 318All of the headers that contain e-mail addresses in a message -- with the 319exception of ``Return-Path:`` which has a stricter syntax -- use this header 320type. That is, ``To:``, ``From:`` etc. 321 322You add a new mailbox header to a HeaderSet by calling the HeaderSet's 323``addMailboxHeader()`` method:: 324 325 $message = new Swift_Message(); 326 $headers = $message->getHeaders(); 327 $headers->addMailboxHeader('Your-Header-Name', [ 328 'person1@example.org' => 'Person Name One', 329 'person2@example.org', 330 'person3@example.org', 331 'person4@example.org' => 'Another named person' 332 ]); 333 334Changing the value of an existing mailbox header is done by calling it's 335``setNameAddresses()`` method:: 336 337 $to = $message->getHeaders()->get('To'); 338 $to->setNameAddresses([ 339 'joe@example.org' => 'Joe Bloggs', 340 'john@example.org' => 'John Doe', 341 'no-name@example.org' 342 ]); 343 344If you don't wish to concern yourself with the complicated accepted input 345formats accepted by ``setNameAddresses()`` as described in the previous chapter 346and you only want to set one or more addresses (not names) then you can just 347use the ``setAddresses()`` method instead:: 348 349 $to = $message->getHeaders()->get('To'); 350 $to->setAddresses([ 351 'joe@example.org', 352 'john@example.org', 353 'no-name@example.org' 354 ]); 355 356.. note:: 357 358 Both methods will accept the above input format in practice. 359 360If all you want to do is set a single address in the header, you can use a 361string as the input parameter to ``setAddresses()`` and/or 362``setNameAddresses()``:: 363 364 $to = $message->getHeaders()->get('To'); 365 $to->setAddresses('joe-bloggs@example.org'); 366 367When output via ``toString()``, a mailbox header produces something like the 368following:: 369 370 $to = $message->getHeaders()->get('To'); 371 $to->setNameAddresses([ 372 'person1@example.org' => 'Name of Person', 373 'person2@example.org', 374 'person3@example.org' => 'Another Person' 375 ]); 376 377 echo $to->toString(); 378 379 /* 380 381 To: Name of Person <person1@example.org>, person2@example.org, Another Person 382 <person3@example.org> 383 384 */ 385 386Internationalized domains are automatically converted to IDN encoding:: 387 388 $to = $message->getHeaders()->get('To'); 389 $to->setAddresses('joe@ëxämple.org'); 390 391 echo $to->toString(); 392 393 /* 394 395 To: joe@xn--xmple-gra1c.org 396 397 */ 398 399ID Headers 400~~~~~~~~~~ 401 402ID headers contain identifiers for the entity (or the message). The most 403notable ID header is the Message-ID header on the message itself. 404 405An ID that exists inside an ID header looks more-or-less less like an email 406address. For example, ``<1234955437.499becad62ec2@example.org>``. The part to 407the left of the @ sign is usually unique, based on the current time and some 408random factor. The part on the right is usually a domain name. 409 410Any ID passed to the header's ``setId()`` method absolutely MUST conform to 411this structure, otherwise you'll get an Exception thrown at you by Swift Mailer 412(a ``Swift_RfcComplianceException``). This is to ensure that the generated 413email complies with relevant RFC documents and therefore is less likely to be 414blocked as spam. 415 416It's easy to add a new ID header to a HeaderSet. You do this by calling the 417HeaderSet's ``addIdHeader()`` method:: 418 419 $message = new Swift_Message(); 420 $headers = $message->getHeaders(); 421 $headers->addIdHeader('Your-Header-Name', '123456.unqiue@example.org'); 422 423Changing the value of an existing ID header is done by calling its ``setId()`` 424method:: 425 426 $msgId = $message->getHeaders()->get('Message-ID'); 427 $msgId->setId(time() . '.' . uniqid('thing') . '@example.org'); 428 429When output via ``toString()``, an ID header produces something like the 430following:: 431 432 $msgId = $message->getHeaders()->get('Message-ID'); 433 echo $msgId->toString(); 434 435 /* 436 437 Message-ID: <1234955437.499becad62ec2@example.org> 438 439 */ 440 441Path Headers 442~~~~~~~~~~~~ 443 444Path headers are like very-restricted mailbox headers. They contain a single 445email address with no associated name. The Return-Path header of a message is a 446path header. 447 448You add a new path header to a HeaderSet by calling the HeaderSet's 449``addPathHeader()`` method:: 450 451 $message = new Swift_Message(); 452 $headers = $message->getHeaders(); 453 $headers->addPathHeader('Your-Header-Name', 'person@example.org'); 454 455Changing the value of an existing path header is done by calling its 456``setAddress()`` method:: 457 458 $return = $message->getHeaders()->get('Return-Path'); 459 $return->setAddress('my-address@example.org'); 460 461When output via ``toString()``, a path header produces something like the 462following:: 463 464 $return = $message->getHeaders()->get('Return-Path'); 465 $return->setAddress('person@example.org'); 466 echo $return->toString(); 467 468 /* 469 470 Return-Path: <person@example.org> 471 472 */ 473 474Header Operations 475----------------- 476 477Working with the headers in a message involves knowing how to use the methods 478on the HeaderSet and on the individual Headers within the HeaderSet. 479 480Adding new Headers 481~~~~~~~~~~~~~~~~~~ 482 483New headers can be added to the HeaderSet by using one of the provided 484``add..Header()`` methods. 485 486The added header will appear in the message when it is sent:: 487 488 // Adding a custom header to a message 489 $message = new Swift_Message(); 490 $headers = $message->getHeaders(); 491 $headers->addTextHeader('X-Mine', 'something here'); 492 493 // Adding a custom header to an attachment 494 $attachment = Swift_Attachment::fromPath('/path/to/doc.pdf'); 495 $attachment->getHeaders()->addDateHeader('X-Created-Time', time()); 496 497Retrieving Headers 498~~~~~~~~~~~~~~~~~~ 499 500Headers are retrieved through the HeaderSet's ``get()`` and ``getAll()`` 501methods:: 502 503 $headers = $message->getHeaders(); 504 505 // Get the To: header 506 $toHeader = $headers->get('To'); 507 508 // Get all headers named "X-Foo" 509 $fooHeaders = $headers->getAll('X-Foo'); 510 511 // Get the second header named "X-Foo" 512 $foo = $headers->get('X-Foo', 1); 513 514 // Get all headers that are present 515 $all = $headers->getAll(); 516 517When using ``get()`` a single header is returned that matches the name (case 518insensitive) that is passed to it. When using ``getAll()`` with a header name, 519an array of headers with that name are returned. Calling ``getAll()`` with no 520arguments returns an array of all headers present in the entity. 521 522.. note:: 523 524 It's valid for some headers to appear more than once in a message (e.g. 525 the Received header). For this reason ``getAll()`` exists to fetch all 526 headers with a specified name. In addition, ``get()`` accepts an optional 527 numerical index, starting from zero to specify which header you want more 528 specifically. 529 530.. note:: 531 532 If you want to modify the contents of the header and you don't know for 533 sure what type of header it is then you may need to check the type by 534 calling its ``getFieldType()`` method. 535 536Check if a Header Exists 537~~~~~~~~~~~~~~~~~~~~~~~~ 538 539You can check if a named header is present in a HeaderSet by calling its 540``has()`` method:: 541 542 $headers = $message->getHeaders(); 543 544 // Check if the To: header exists 545 if ($headers->has('To')) { 546 echo 'To: exists'; 547 } 548 549 // Check if an X-Foo header exists twice (i.e. check for the 2nd one) 550 if ($headers->has('X-Foo', 1)) { 551 echo 'Second X-Foo header exists'; 552 } 553 554If the header exists, ``true`` will be returned or ``false`` if not. 555 556.. note:: 557 558 It's valid for some headers to appear more than once in a message (e.g. 559 the Received header). For this reason ``has()`` accepts an optional 560 numerical index, starting from zero to specify which header you want to 561 check more specifically. 562 563Removing Headers 564~~~~~~~~~~~~~~~~ 565 566Removing a Header from the HeaderSet is done by calling the HeaderSet's 567``remove()`` or ``removeAll()`` methods:: 568 569 $headers = $message->getHeaders(); 570 571 // Remove the Subject: header 572 $headers->remove('Subject'); 573 574 // Remove all X-Foo headers 575 $headers->removeAll('X-Foo'); 576 577 // Remove only the second X-Foo header 578 $headers->remove('X-Foo', 1); 579 580When calling ``remove()`` a single header will be removed. When calling 581``removeAll()`` all headers with the given name will be removed. If no headers 582exist with the given name, no errors will occur. 583 584.. note:: 585 586 It's valid for some headers to appear more than once in a message (e.g. 587 the Received header). For this reason ``remove()`` accepts an optional 588 numerical index, starting from zero to specify which header you want to 589 check more specifically. For the same reason, ``removeAll()`` exists to 590 remove all headers that have the given name. 591 592Modifying a Header's Content 593~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 594 595To change a Header's content you should know what type of header it is and then 596call it's appropriate setter method. All headers also have a 597``setFieldBodyModel()`` method that accepts a mixed parameter and delegates to 598the correct setter:: 599 600The header will be updated inside the HeaderSet and the changes will be seen 601when the message is sent:: 602 603 $headers = $message->getHeaders(); 604 605 // Change the Subject: header 606 $subj = $headers->get('Subject'); 607 $subj->setValue('new subject here'); 608 609 // Change the To: header 610 $to = $headers->get('To'); 611 $to->setNameAddresses([ 612 'person@example.org' => 'Person', 613 'thing@example.org' 614 ]); 615 616 // Using the setFieldBodyModel() just delegates to the correct method 617 // So here to calls setNameAddresses() 618 $to->setFieldBodyModel([ 619 'person@example.org' => 'Person', 620 'thing@example.org' 621 ]); 622