/** * Get the raw email data sent by this object. * * @param boolean $stream If true, return a stream resource, otherwise * a string is returned. * * @return stream|string The raw email data. * @since 2.4.0 */ public function getRaw($stream = true) { if ($stream) { $hdr = new Horde_Stream(); $hdr->add($this->_headers->toString(), true); return Horde_Stream_Wrapper_Combine::getStream(array($hdr->stream, $this->getBasePart()->toString(array('stream' => true)))); } return $this->_headers->toString() . $this->_getBasePart->toString(); }
/** * Get the raw email data sent by this object. * * @param boolean $stream If true, return a stream resource, otherwise * a string is returned. * * @return stream|string The raw email data. * @since 2.4.0 */ public function getRaw($stream = true) { if ($stream) { $hdr = new Horde_Stream(); $hdr->add($this->_headers->toString(), true); return Horde_Stream_Wrapper_Combine::getStream(array($hdr->stream, $this->getBasePart()->toString(array('stream' => true, 'encode' => Horde_Mime_Part::ENCODE_7BIT | Horde_Mime_Part::ENCODE_8BIT | Horde_Mime_Part::ENCODE_BINARY)))); } return $this->_headers->toString() . $this->getBasePart()->toString(); }
/** * Generate the MDN according to the specifications listed in RFC * 3798 [3]. * * @param boolean $action Was this MDN type a result of a manual * action on part of the user? * @param boolean $sending Was this MDN sent as a result of a manual * action on part of the user? * @param string $type The type of action performed by the user. * Per RFC 3798 [3.2.6.2] the following types are * valid: * - deleted * - displayed * @param string $name The name of the local server. * @param Horde_Mail_Transport $mailer Mail transport object. * @param array $opts Additional options: * - charset: (string) Default charset. * DEFAULT: NONE * - from_addr: (string) From address. * DEFAULT: NONE * @param array $mod The list of modifications. Per RFC 3798 * [3.2.6.3] the following modifications are * valid: * - error * @param array $err If $mod is 'error', the additional * information to provide. Key is the type of * modification, value is the text. */ public function generate($action, $sending, $type, $name, $mailer, array $opts = array(), array $mod = array(), array $err = array()) { $opts = array_merge(array('charset' => null, 'from_addr' => null), $opts); if (!($hdr = $this->_headers[self::MDN_HEADER])) { throw new RuntimeException('Need at least one address to send MDN to.'); } $to = $hdr->getAddressList(true); $ua = Horde_Mime_Headers_UserAgent::create(); if ($orig_recip = $this->_headers['Original-Recipient']) { $orig_recip = $orig_recip->value_single; } /* Set up the mail headers. */ $msg_headers = new Horde_Mime_Headers(); $msg_headers->addHeaderOb(Horde_Mime_Headers_MessageId::create()); $msg_headers->addHeaderOb($ua); /* RFC 3834 [5.2] */ $msg_headers->addHeader('Auto-Submitted', 'auto-replied'); $msg_headers->addHeaderOb(Horde_Mime_Headers_Date::create()); if ($opts['from_addr']) { $msg_headers->addHeader('From', $opts['from_addr']); } $msg_headers->addHeader('To', $to); $msg_headers->addHeader('Subject', Horde_Mime_Translation::t("Disposition Notification")); /* MDNs are a subtype of 'multipart/report'. */ $msg = new Horde_Mime_Part(); $msg->setType('multipart/report'); $msg->setContentTypeParameter('report-type', 'disposition-notification'); /* The first part is a human readable message. */ $part_one = new Horde_Mime_Part(); $part_one->setType('text/plain'); $part_one->setCharset($opts['charset']); if ($type == 'displayed') { $contents = sprintf(Horde_Mime_Translation::t("The message sent on %s to %s with subject \"%s\" has been displayed.\n\nThis is no guarantee that the message has been read or understood."), $this->_headers['Date'], $this->_headers['To'], $this->_headers['Subject']); $flowed = new Horde_Text_Flowed($contents, $opts['charset']); $flowed->setDelSp(true); $part_one->setContentTypeParameter('format', 'flowed'); $part_one->setContentTypeParameter('DelSp', 'Yes'); $part_one->setContents($flowed->toFlowed()); } // TODO: Messages for other notification types. $msg[] = $part_one; /* The second part is a machine-parseable description. */ $part_two = new Horde_Mime_Part(); $part_two->setType('message/disposition-notification'); $part_two_h = new Horde_Mime_Headers(); $part_two_h->addHeader('Reporting-UA', $name . '; ' . $ua); if (!empty($orig_recip)) { $part_two_h->addHeader('Original-Recipient', 'rfc822;' . $orig_recip); } if ($opts['from_addr']) { $part_two_h->addHeader('Final-Recipient', 'rfc822;' . $opts['from_addr']); } if ($msg_id = $this->_headers['Message-ID']) { $part_two_h->addHeader('Original-Message-ID', strval($msg_id)); } /* Create the Disposition field now (RFC 3798 [3.2.6]). */ $dispo = ($action ? 'manual-action' : 'automatic-action') . '/' . ($sending ? 'MDN-sent-manually' : 'MDN-sent-automatically') . '; ' . $type; if (!empty($mod)) { $dispo .= '/' . implode(', ', $mod); } $part_two_h->addHeader('Disposition', $dispo); if (in_array('error', $mod) && isset($err['error'])) { $part_two_h->addHeader('Error', $err['error']); } $part_two->setContents(trim($part_two_h->toString()) . "\n"); $msg[] = $part_two; /* The third part is the text of the original message. RFC 3798 [3] * allows us to return only a portion of the entire message - this * is left up to the user. */ $part_three = new Horde_Mime_Part(); $part_three->setType('message/rfc822'); $part_three_text = array(trim($this->_headers->toString()) . "\n"); if (!empty($this->_msgtext)) { $part_three_text[] = "\n" . $this->_msgtext; } $part_three->setContents($part_three_text); $msg[] = $part_three; return $msg->send($to, $msg_headers, $mailer); }
/** * Generate the MDN according to the specifications listed in RFC * 3798 [3]. * * @param boolean $action Was this MDN type a result of a manual * action on part of the user? * @param boolean $sending Was this MDN sent as a result of a manual * action on part of the user? * @param string $type The type of action performed by the user. * Per RFC 3798 [3.2.6.2] the following types are * valid: * - deleted * - displayed * @param string $name The name of the local server. * @param Mail $mailer A Mail driver. * @param array $opts Additional options: * - charset: (string) Default charset. * DEFAULT: NONE * - from_addr: (string) From address. * DEFAULT: NONE * @param array $mod The list of modifications. Per RFC 3798 * [3.2.6.3] the following modifications are * valid: * - error * @param array $err If $mod is 'error', the additional * information to provide. Key is the type of * modification, value is the text. * * @throws Horde_Mime_Exception */ public function generate($action, $sending, $type, $name, $mailer, array $opts = array(), array $mod = array(), array $err = array()) { $opts = array_merge(array('charset' => null, 'from_addr' => null), $opts); $to = $this->getMdnReturnAddr(); $ua = $this->_headers->getUserAgent(); $orig_recip = $this->_headers->getValue('Original-Recipient'); if (!empty($orig_recip) && is_array($orig_recip)) { $orig_recip = $orig_recip[0]; } $msg_id = $this->_headers->getValue('Message-ID'); /* Create the Disposition field now (RFC 3798 [3.2.6]). */ $dispo = 'Disposition: ' . ($action ? 'manual-action' : 'automatic-action') . '/' . ($sending ? 'MDN-sent-manually' : 'MDN-sent-automatically') . '; ' . $type; if (!empty($mod)) { $dispo .= '/' . implode(', ', $mod); } /* Set up the mail headers. */ $msg_headers = new Horde_Mime_Headers(); $msg_headers->addMessageIdHeader(); $msg_headers->addUserAgentHeader($ua); $msg_headers->addHeader('Date', date('r')); if ($opts['from_addr']) { $msg_headers->addHeader('From', $opts['from_addr']); } $msg_headers->addHeader('To', $this->getMdnReturnAddr()); $msg_headers->addHeader('Subject', Horde_Mime_Translation::t("Disposition Notification")); /* MDNs are a subtype of 'multipart/report'. */ $msg = new Horde_Mime_Part(); $msg->setType('multipart/report'); $msg->setContentTypeParameter('report-type', 'disposition-notification'); /* The first part is a human readable message. */ $part_one = new Horde_Mime_Part(); $part_one->setType('text/plain'); $part_one->setCharset($opts['charset']); if ($type == 'displayed') { $contents = sprintf(Horde_Mime_Translation::t("The message sent on %s to %s with subject \"%s\" has been displayed.\n\nThis is no guarantee that the message has been read or understood."), $this->_headers->getValue('Date'), $this->_headers->getValue('To'), $this->_headers->getValue('Subject')); $flowed = new Horde_Text_Flowed($contents, $opts['charset']); $flowed->setDelSp(true); $part_one->setContentTypeParameter('format', 'flowed'); $part_one->setContentTypeParameter('DelSp', 'Yes'); $part_one->setContents($flowed->toFlowed()); } // TODO: Messages for other notification types. $msg->addPart($part_one); /* The second part is a machine-parseable description. */ $part_two = new Horde_Mime_Part(); $part_two->setType('message/disposition-notification'); $part_two_text = array('Reporting-UA: ' . $name . '; ' . $ua . "\n"); if (!empty($orig_recip)) { $part_two_text[] = 'Original-Recipient: rfc822;' . $orig_recip . "\n"; } if ($opts['from_addr']) { $part_two_text[] = 'Final-Recipient: rfc822;' . $opts['from_addr'] . "\n"; } if (!empty($msg_id)) { $part_two_text[] = 'Original-Message-ID: rfc822;' . $msg_id . "\n"; } $part_two_text[] = $dispo . "\n"; if (in_array('error', $mod) && isset($err['error'])) { $part_two_text[] = 'Error: ' . $err['error'] . "\n"; } $part_two->setContents($part_two_text); $msg->addPart($part_two); /* The third part is the text of the original message. RFC 3798 [3] * allows us to return only a portion of the entire message - this * is left up to the user. */ $part_three = new Horde_Mime_Part(); $part_three->setType('message/rfc822'); $part_three_text = array($this->_headers->toString()); if (!empty($this->_msgtext)) { $part_three_text[] = $part_three->getEOL() . $this->_msgtext; } $part_three->setContents($part_three_text); $msg->addPart($part_three); return $msg->send($to, $msg_headers, $mailer); }
/** * Send a redirect (a/k/a resent) message. See RFC 5322 [3.6.6]. * * @param mixed $to The addresses to redirect to. * @param boolean $log Whether to log the resending in the history and * sentmail log. * * @return array An object with the following properties for each * redirected message: * - contents: (IMP_Contents) The contents object. * - headers: (Horde_Mime_Headers) The header object. * - mbox: (IMP_Mailbox) Mailbox of the message. * - uid: (string) UID of the message. * * @throws IMP_Compose_Exception */ public function sendRedirectMessage($to, $log = true) { global $injector, $registry; $recip = $this->recipientList(array('to' => $to)); $identity = $injector->getInstance('IMP_Identity'); $from_addr = $identity->getFromAddress(); $out = array(); foreach ($this->getMetadata('redirect_indices') as $val) { foreach ($val->uids as $val2) { try { $contents = $injector->getInstance('IMP_Factory_Contents')->create($val->mbox->getIndicesOb($val2)); } catch (IMP_Exception $e) { throw new IMP_Compose_Exception(_("Error when redirecting message.")); } $headers = $contents->getHeader(); /* We need to set the Return-Path header to the current user - * see RFC 2821 [4.4]. */ $headers->removeHeader('return-path'); $headers->addHeader('Return-Path', $from_addr); /* Generate the 'Resent' headers (RFC 5322 [3.6.6]). These * headers are prepended to the message. */ $resent_headers = new Horde_Mime_Headers(); $resent_headers->addHeader('Resent-Date', date('r')); $resent_headers->addHeader('Resent-From', $from_addr); $resent_headers->addHeader('Resent-To', $recip['header']['to']); $resent_headers->addHeader('Resent-Message-ID', Horde_Mime_Headers_MessageId::create()); $header_text = trim($resent_headers->toString(array('encode' => 'UTF-8'))) . "\n" . trim($contents->getHeader(IMP_Contents::HEADER_TEXT)); $this->_prepSendMessageAssert($recip['list']); $to = $this->_prepSendMessage($recip['list']); $hdr_array = $headers->toArray(array('charset' => 'UTF-8')); $hdr_array['_raw'] = $header_text; try { $injector->getInstance('IMP_Mail')->send($to, $hdr_array, $contents->getBody()); } catch (Horde_Mail_Exception $e) { $e2 = new IMP_Compose_Exception($e); if (($prev = $e->getPrevious()) && $prev instanceof Horde_Smtp_Exception) { if ($prev instanceof Horde_Smtp_Exception_Recipients) { $e2 = new IMP_Compose_Exception_Addresses($e); foreach ($prev->recipients as $val) { $e2->addAddress(new Horde_Mail_Rfc822_Address($val), _("Address rejected by the sending mail server."), $e2::BAD); } } Horde::log(sprintf("SMTP Error: %s (%u; %s)", $prev->raw_msg, $prev->getCode(), $prev->getEnhancedSmtpCode() ?: 'N/A'), 'ERR'); $e2->logged = true; } throw $e2; } $recipients = strval($recip['list']); Horde::log(sprintf("%s Redirected message sent to %s from %s", $_SERVER['REMOTE_ADDR'], $recipients, $registry->getAuth()), 'INFO'); if ($log && ($tmp = $headers['Message-ID'])) { $msg_id = reset($tmp->getIdentificationOb()->ids); /* Store history information. */ $injector->getInstance('IMP_Maillog')->log(new IMP_Maillog_Message($msg_id), new IMP_Maillog_Log_Redirect(array('msgid' => reset($resent_headers->getIdentificationOb()->ids), 'recipients' => $recipients))); $injector->getInstance('IMP_Sentmail')->log(IMP_Sentmail::REDIRECT, $msg_id, $recipients); } $tmp = new stdClass(); $tmp->contents = $contents; $tmp->headers = $headers; $tmp->mbox = $val->mbox; $tmp->uid = $val2; $out[] = $tmp; } } return $out; }
/** * Send a redirect (a/k/a resent) message. See RFC 5322 [3.6.6]. * * @param mixed $to The addresses to redirect to. * @param boolean $log Whether to log the resending in the history and * sentmail log. * * @return array An object with the following properties for each * redirected message: * - contents: (IMP_Contents) The contents object. * - headers: (Horde_Mime_Headers) The header object. * - mbox: (IMP_Mailbox) Mailbox of the message. * - uid: (string) UID of the message. * * @throws IMP_Compose_Exception */ public function sendRedirectMessage($to, $log = true) { global $injector, $registry; $recip = $this->recipientList(array('to' => $to)); $identity = $injector->getInstance('IMP_Identity'); $from_addr = $identity->getFromAddress(); $out = array(); foreach ($this->getMetadata('redirect_indices') as $val) { foreach ($val->uids as $val2) { try { $contents = $injector->getInstance('IMP_Factory_Contents')->create($val->mbox->getIndicesOb($val2)); } catch (IMP_Exception $e) { throw new IMP_Compose_Exception(_("Error when redirecting message.")); } $headers = $contents->getHeader(); /* We need to set the Return-Path header to the current user - * see RFC 2821 [4.4]. */ $headers->removeHeader('return-path'); $headers->addHeader('Return-Path', $from_addr); /* Generate the 'Resent' headers (RFC 5322 [3.6.6]). These * headers are prepended to the message. */ $resent_headers = new Horde_Mime_Headers(); $resent_headers->addHeader('Resent-Date', date('r')); $resent_headers->addHeader('Resent-From', $from_addr); $resent_headers->addHeader('Resent-To', $recip['header']['to']); $resent_headers->addHeader('Resent-Message-ID', Horde_Mime::generateMessageId()); $header_text = trim($resent_headers->toString(array('encode' => 'UTF-8'))) . "\n" . trim($contents->getHeader(IMP_Contents::HEADER_TEXT)); $this->_prepSendMessageAssert($recip['list']); $to = $this->_prepSendMessage($recip['list']); $hdr_array = $headers->toArray(array('charset' => 'UTF-8')); $hdr_array['_raw'] = $header_text; try { $injector->getInstance('IMP_Mail')->send($to, $hdr_array, $contents->getBody()); } catch (Horde_Mail_Exception $e) { throw new IMP_Compose_Exception($e); } $recipients = strval($recip['list']); Horde::log(sprintf("%s Redirected message sent to %s from %s", $_SERVER['REMOTE_ADDR'], $recipients, $registry->getAuth()), 'INFO'); if ($log) { /* Store history information. */ $msg_id = new Horde_Mail_Rfc822_Identification($headers->getValue('message-id')); $injector->getInstance('IMP_Maillog')->log(new IMP_Maillog_Message(reset($msg_id->ids)), new IMP_Maillog_Log_Redirect($recipients)); $injector->getInstance('IMP_Sentmail')->log(IMP_Sentmail::REDIRECT, reset($msg_id->ids), $recipients); } $tmp = new stdClass(); $tmp->contents = $contents; $tmp->headers = $headers; $tmp->mbox = $val->mbox; $tmp->uid = $val2; $out[] = $tmp; } } return $out; }