Email implements a simple interface to send mail
This class can be used to send mail from Website@School, e.g. alerts, new passwords, feedback to the project (with attached translations), etc.
Typical use:
require_once('email.class.php'); $mailer = new Email; $mailer->set_mailto($email,$name); $mailer->set_subject($subject); $mailer->set_message($message); $mailer->add_attachment($data,$name); $mailer->send();
Located in /program/lib/email.class.php (line 45)
constructor resets all variables to a known (default) state
add an attachment
This simply adds an attachment with associated properties. Multiple attachments can be added by calling this routine multiple times.
The attachments added via this routine are simply added to the current list of attachments in $this->attachments. There is also another routine (@link add_related()} which takes care of attachments in a multipart/related context. Both routines do add to the same array.
add an address and name for the Cc: header
Embedded CRs LFs "<" and "> are removed from $addr, and the result is stored, together with $name. Note that this function can be called multiple times, where each call adds an address to the list.
add an (alternative version of) message
This simply stores an alternative message body until it can be combined (to a multipart/alternative) and subsequently sent.
Note that according to RFC1341 the sender should place body parts in increasing order of preference, ie. first text/plain, then text/html and finally application/pdf. However, it is up to the caller to call and add_message() in the correct order.
add a related attachment
This adds a related attachment with associated properties. Multiple related attachments can be added by calling this routine multiple times.
The attachments added via this routine are added to the current list of attachments in $this->attachments, but they are handled in a slightly different way once the mail body is constructed. There is another routine (@link add_attachment()} which takes care of 'plain' attachments (which usually leads to a multipart/mixed message). Both routines add to the same array.
Note 1: all related attachments are assigned a (hopefully globally) unique Content-ID. This ID can be used to refer to this message part, e.g. via HTML img-tags src="cid:$content_id". See also RFC2111. The Content-ID adheres to the same rules as a Message-ID, hence we use the same routine for both.
Note 2: once a related attachment is added via this routine, the flag $this->related is set tot TRUE, making sure we eventually generate a multipart/related rather than a multipart/mixed message.
construct a unique boundary for use within this mail message
the combination of our pid, the current date up to a second and a unique number within this run should provide enough uniqueness within this mail message. The maximum length of the resulting string is at most 44 characters (assuming signed integers take at most 11 positions in decimal form). However, as a rule get_unique_number() starts with a single '1' so a practical max length of 34 is far more likely.
encode the main message, optionally including 1 or more alternative versions
this encodes the main message as a single body part. If there are alternative versions of the message, all variants are wrapped in a multipart/alternative body part.
Depending on the $toplevel flag the associated headers are either appended to the $body ($toplevel==FALSE) OR added to the $headers array ($toplevel==TRUE).
The actual encoding is done in encode_part().
encode an email body part with headers and all
this encodes the message or attachment in $source with the correct mime type and other headers. Depending on the $toplevel flag, the headers end up in the $body (as part of a multipart mime message) OR in the $headers array (if the caller has decided that there is only a single body part in this email message).
The necessary headers are computed in a separate routine encode_part_headers().
construct necessary headers for a MIME body part
this routine constructs the following headers:
a small utility routine to determine if a string has only 7bit characters
construct the full mail body and the necessary top-level mail header fields
this routine examines the messages that were added to Email (in $this->messages): that array could contain 0, 1 or more versions of the message to send. Also this routine looks at the 0, 1 or more plain or related attachments that were added to $this->attachments.
If there are multiple entries in $this->messages, those are wrapped in a multipart/alternative body part. If there is only a single message it becomes one of the body parts in its own right. If there are any attachments, both the message (which might be multipart/alternative) and the attachments are combined using either multipart/mixed (there are only plain attachments) or multipart/related (there was at least one related attachment).
The resulting mail body is returned to the caller via &$body. Hopefully this saves some memory moving that possibly big string around. The headers that need to go in the mail headers are returned via &$headers. It is the responsabilty of the caller to make sure that these headers end up in the correct place.
reset all variables to their default values
encode an 8-bit byte according to Q-encoding in RFC2047
This routine encodes a single integer ASCII code into either
If $minimal is TRUE, only digits "0" - "9" and letters "A" - "Z" and "a" - "z" use literal representation and character 32 " " uses generic 8bit encoding "=20".
The latter case yields only digits, letters, equal-sign and question mark, which should travel undisturbed through any mail transdfer agent.
There is a special situation when encoding UTF8 where characters can span multiple octets. The length of such a sequence can be determined by the number of most significant 1's in a row in the first octet. If $c is the first octet of a UTF8-sequence, we tell the caller the total length of the encoded sequence, not just the length of the encoded 1st octet (which would always be 3). This forces the caller to start a new 'encoded-word' with enough room for the complete sequence if necessary, preventing a multi-octet sequence to span two 'encoded-words'. Note that characters in a UTF8-tail yield length 3, even when more UTF8-tail octets follow. That is OK because the first character already 'reserved' the space when the first octet was processed.
Here is a small truth table for sequence lengths (see also RFC3629). bit pattern range len comments 0xxx.xxxx 0-127 3 ASCII 10xx.xxxx 128-191 3 octet is part of UTF8-tail 110x.xxxx 192-223 6 UTF8-2, beginning of a sequence of 2 octets 1110.xxxx 224-239 9 UTF8-3, beginning of a sequence of 3 octets 1111.0xxx 240-247 12 UTF8-4, beginning of a sequence of 4 octets 1111.10xx 248-251 3 sequence of 5 characters not defined in RFC3929, settle for length 3 1111.110x 252-253 3 sequence of 6 characters not defined in RFC3929, settle for length 3 1111.111x 254-255 3 no sequence at all, settle for length 3
Note that if $c is NOT UTF8 but say ISO-5988-1, the worst that can happen is that a perfectly valid single octet character in the range 192-247 would indicat a length of more than the necessary 3, pushing up to 4 characters to the next 'encoded-word'. Oh well, I can live with that.
References: http://www.ietf.org/rfc/rfc2047.txt, http://www.ietf.org/rfc/rfc3629.txt.
encode a string according to RFC2047 (Message Header Extensions for Non-ASCII Text)
This routine encodes $source according to RFC2047 (Message Header Extensions for Non-ASCII Text) using the 'Q'-encoding (somewhat comparable to quoted_printable). However, if the $source uses only harmless 7bit characters and falls within the limit of $remaining characters it is returned unchanged and the number of $remaining characters is updated accordingly.
In all other cases ($source contains bytes > 127, $source is longer than $remaining, etc.) this encodes the string into 'encoded-word's of max 75 chars. These 'encoded-word's look like this:
"=?" charset "?" encoding "?" encoded-text "?="with 'encoding' always equal to "Q" (similar to quoted printable). The actual encoding of characters is done in rfc2047_qchar(). The boolean flag $minimal can be used to limit the literal representation to only digits and letters, using generic 8bit encoding by setting it to TRUE.
If multiple 'encoded-word's are necessary, they are separated from each other by a folding space, i.e. newline (using $eol) followed by a normal space (ASCII 32). The end result never ends with such a folding space; the returned value always ends with the "?=" of the last 'encoded-word'.
Note 1: I found it quite hard to read the combination of RFC5322 and RFC2047 because I had some trouble distinguishing the rules for RFC5322-type headers. I finally settled for this simplified set
Note 2: I have not implemented fancy and streamlined code to minimise the amount of encoded characters, ie. leaving pure ASCII-words unencoded and encoding only non-ASCII words or words containing "=?" because I could not invest that amount of time. Maybe in a later version... (famous last words). I did optimise for short and pure and simple ASCII strings because I expect that generated Subject: headers and other headers will be ASCII most of the time. We'll see how that works out.
Note 3: Quirk: if initially there is not enough space for the shortest possible 'encoded-word', we insert a FWS even if $source has no WSP at that point. Basically it means that we add a character to the result. This may or may not be a problem for the caller. OTOH: the caller should provide enough space in the first place, so there.
References: see http://www.ietf.org/rfc/rfc2047.txt and http://www.ietf.org/rfc/rfc5322.txt.
construct an address field according to RFC5322 (RFC822)
This routine constructs an address according to (simplified) rules in RFC5322 section 3.4. Depending on the $legacy flag, the parameters are used to construct either an 'angle-addr'
DQUOT $display_name DQUOT SPACE "<" $addr_spec ">"or an address with the display-name "hidden" in a comment
$addr_spec SPACE "(" $display_name ")"
Basically the $addr_spec is not modified; it is assumed that this string obeys the rules for 'addr-spec' in RFC5322. Specifically we do not encode this information (with rfc2047_qstring() or otherwise). However, we DO strip any CR and/or LF characters because these might cause problems lateron (eg. an unwanted extra blank line in the mail headers). Also, we definately do not want to have angle brackets, so we remove those too, just to be sure.
The $display_name can be modified. Reading RFC5322 yields the following (simplified) rules. 'display-name' => 'phrase' => 1*'word'; 'word' => 'atom' | 'quoted-string'. In other words: it is allowed to use a quoted string, ie.
If the legacy-flag is set, we use the parameter $display_name to construct a (simplified) comment, ie.
Note: All this cleaning up of CR, LF, DQUOTE, etc. does NOT weed out other CTLs (ASCII 0...ASCII 31).
construct a message-id conforming to RFC5322 (RFC2822, RFC822)
This constructs a message id according to specifications in section 3.6.4 in RFC5322 Internet Message Format (October 2008), see http://www.ietf.org/rfc/rfc5322.txt.
Note that the 'id-left' in the 'msg-id' also contains the remote IP-address. This could be an IPv4 address in the usual dotted-decimal form but it could also be an IPv6 address like '::1' (3 characters) or '[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]' (41 characters). The total maximum-length of 'id-left' may add up to 11 (32-bit signed pid) + 1 (dot) + 41 (full IPv6 w/ brackets) + 1 (hash) + 11 (32-bit signed remote port) + 1 (dot) + 14 (date/time) + 11 (signed unique number) = 91 characters. This is longer than the recommended linelength of 78 characters, but the absolute maximum of 998 characters will probably NOT be reached. OTOH: we do not actually check for huge domain names and/or server names. Oh well.
Note that we massage the IPv6 address by replacing any ':', '[' and ']' with '!', '{' and '}' respectively because the former are not allowed in a dot-atom-text. As a matter of fact we translate most 'specials' to 'atext' (RFC5322 3.2.3). Notable exception: the dot stays.
send the message using the prepared information (To:, Subject:, the message and attachments etc.)
this routine prepares the raw message + necessary headers and subsequently sends the message.
actually send a prepared mail body (with headers) to recipient(s)
this routine constructs the necessary header fields ('To', 'Subject', 'From', 'Reply-To', 'Cc', 'X-Mailer', etc. and subsequently sends $message to the recipient(s).
Note that there are several sources for headers: we start with $this->headers, followed by the list of headers mentioned above and ending with the headers in $message_headers. This means that $message_headers has the last word in headers; existing headers in $headers will be overwritten with headers present in $message_headers. As a rule at most the following headers are set in $message_headers: 'MIME-Version', 'Content-Type', 'Content-Transfer-Encoding' and 'Message-ID:'.
manually add a header to the mail message
This adds a header to the message headers. Possible candidates are
record the address and the name for the From: header
Embedded CRs LFs "<" and "> are removed from $addr, and the result is stored, together with $name.
record the address and the name for the Reply-To: header
Embedded CRs LFs "<" and "> are removed from $addr, and the result is stored, together with $name.
record the address and the name for the To: header
Embedded CRs LFs "<" and ">" are removed from $addr, and the result is stored, together with $name.
set the (primary) message
This simply stores the message primary body until it can be sent. Many times there is just a single message (perhaps with attachments), but it is possible to add an alternative message via add_message(). In that case the array $this->messages[] holds more than 1 variation of the message. This routine always stores 'the' message, i.e. if there was a set of messages before, those will be removed and an array with a single message remains.
Note that according to RFC1341 the sender should place body parts in increasing order of preference, ie. first text/plain, then text/html and finally application/pdf. However, it is up to the caller to call and add_message() in the correct order.
store the subject of the mail message
Embedded CRs and LFs in $subject are removed and the result is stored until message send time.
Documentation generated on Tue, 28 Jun 2016 19:09:14 +0200 by phpDocumentor 1.4.0