EllisLab text mark
Advanced Search
     
[CI 1.7 rev 1572+] Email Class - html email problems
Posted: 19 November 2008 02:11 PM   [ Ignore ]
Joined: 2007-04-03
118 posts

I went through the various threads for people having problems sending html emails.  Mostly a lot of issues with carriage returns or having problems finding the config file, etc.  Originally I was trying to play with all those things (crlf, etc.) to no avail, so I decided to dig through the code.

I should probably state the following platform conditions just to be complete:
Apache on Windows Box, Outlook 2007 MUA, and using mail protocol.

What I found in the Email class was really confusing how it would work for anyone.  Basically it appears that when sending html emails the Email class would put part of the message (the alternate message) in the header, and the other part (the html message) in the body.  What I had read elsewhere is to put both the alternate and html messages in the body, and let the MUA pick which one of those “body” messages to use.

Using the original version of the Email class I had all sorts of weird things happening, carriage return problems in the message and subject line, html tags coming through, part of both message types would show up in the body, etc. etc.

I noticed some inconsistency in the library’s handling and took a stab at fixing it. I just attached my version since I figured that would make it easiest for someone to do a diff on it.  I created two little helper methods just so the repetitive coding could be eliminated and make it easier to maintain.

Anyway, with the attached changes, all of the problems I mentioned having were solved.  I have a whole bunch test emails showing the source code of the emails and how screwed up it was, but I’ll refrain from posting unless someone requests it.  I think the attached code illustrates the problem sufficiently by itself.

I’ll post a peek of the portion of the code I altered in the next post.  (Post #3 has corrected version of code).

 
Posted: 19 November 2008 02:11 PM   [ Ignore ]   [ # 1 ]   [ Rating: 0 ]
Joined: 2007-04-03
118 posts
//new method for maintainability/consistency, etc.
    
function _get_content_type_header($type 'html')
    
{
        
if ($type == 'multi'{
            
return "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" $this->newline;
        
}
        
return "Content-Type: text/".$type."; charset=" $this->charset $this->newline;
    
}

//new method for maintainability/consistency, etc.
    
function _get_content_encoding_header($type 'data')
    
{
        
if ($type == 'quoted-printable'{
            
return "Content-Transfer-Encoding: quoted-printable";
        
}
        
return "Content-Transfer-Encoding: " $this->_get_encoding();
    
}

    
/**
     * Build Final Body and attachments
     *
     * @access    private
     * @return    void
     */
    
function _build_message()
    
{
        
if ($this->wordwrap === TRUE  AND  $this->mailtype != 'html')
        
{
            $this
->_body $this->word_wrap($this->_body);
        
}

        $this
->_set_boundaries();
        
$this->_write_headers();

        
$hdr = ($this->_get_protocol() == 'mail') ? $this->newline '';

        switch (
$this->_get_content_type())
        
{
            
case 'plain' :

//              $hdr .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
                
$hdr .= $this->_get_content_type_header($type 'plain');
//              $hdr .= "Content-Transfer-Encoding: " . $this->_get_encoding();
                
$hdr .= $this->_get_content_encoding_header();

                if (
$this->_get_protocol() == 'mail')
                
{
                    $this
->_header_str .= $hdr;
                    
$this->_finalbody $this->_body;

                    return;
                
}

                $hdr 
.= $this->newline $this->newline $this->_body;

                
$this->_finalbody $hdr;
                return;

            break;
            case 
'html' :

                if (
$this->send_multipart === FALSE)
                
{
//                    $hdr .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
                    
$hdr .= $this->_get_content_type_header($type 'html');
//                    $hdr .= "Content-Transfer-Encoding: quoted-printable";
                    
$hdr .= $this->_get_content_encoding_header('quoted-printable');
                
}
                
else
                
{
                    
// add one additional header of Content-type:multipart/alternative and
                    // boundary string that marks the different areas of the email.
                    // Note that the content type of the message itself is sent as a mail header,
                    // while the content types of the individual parts of the message are embedded
                    // in the message itself.
                    // This way, mail clients can decide which part of the message they want to display.
//                    $hdr .= "Content-Type: multipart/alternative; boundary=\"" . $this->_alt_boundary . "\"" . $this->newline;
                    
$hdr .= $this->_get_content_type_header($type 'multi');
                    
$hdr .= $this->_get_mime_message() . $this->newline $this->newline;

//NOTE to CI Developers:  originally the plain (alternate) type message was included in the header
//instead of being included as an alternate message in the message body?!
//I broke this out into different variables to it was easier to see here:
                    // the alternate (plain) part of the message:
                    
$alt  "--" $this->_alt_boundary $this->newline;
//                  $alt .= "Content-Type: text/plain; charset=" . $this->charset . $this->newline;
                    
$alt .= $this->_get_content_type_header($type 'plain');
//                    $alt .= "Content-Transfer-Encoding: " . $this->_get_encoding() . $this->newline . $this->newline;
                    
$alt .= $this->_get_content_encoding_header() . $this->newline $this->newline;
                    
// add the message body:
                    
$alt .= $this->_get_alt_message() . $this->newline $this->newline;

                    
// the html part of the message:
                    
$html  "--" $this->_alt_boundary $this->newline;
//                  $html .= "Content-Type: text/html; charset=" . $this->charset . $this->newline;
                    
$html .= $this->_get_content_type_header($type 'html');
//NOTE to CI Developers:  the two trailing newlines were missing here.
//                  $html .= "Content-Transfer-Encoding: quoted-printable";
                    
$html .= $this->_get_content_encoding_header('quoted-printable') . $this->newline $this->newline;
                    
// add the message body:
                    
$html .= $this->_prep_quoted_printable($this->_body) . $this->newline $this->newline;
                
}

//this needs to be altered slightly because $alt, $html won't be defined for one case above.
//                $this->_body = $this->_prep_quoted_printable($this->_body);
                
$this->_body $alt $html;

                if (
$this->_get_protocol() == 'mail')
                
{
                    $this
->_header_str .= $hdr;
//                    $this->_finalbody = $this->_body . $this->newline . $this->newline;
                    
$this->_finalbody $this->_body
 
Posted: 19 November 2008 02:20 PM   [ Ignore ]   [ # 2 ]   [ Rating: 0 ]
Joined: 2007-04-03
118 posts

I noticed the above and attached will have $html undefined after posting.  Probably just needs a little tweak:

case 'html' :

                
$this->_body $this->_prep_quoted_printable($this->_body);

                if (
$this->send_multipart === FALSE)
                
{
                    
...
                
}
                
else
                
{
                    
...
                    
$this->_body $alt $html $this->_body;
                
}


                
if ($this->_get_protocol() == 'mail'
 
Posted: 19 November 2008 02:31 PM   [ Ignore ]   [ # 3 ]   [ Rating: 0 ]
Joined: 2007-04-03
118 posts

Here’s modified version based on above comments.

 
Posted: 15 December 2008 02:31 PM   [ Ignore ]   [ # 4 ]   [ Rating: 0 ]
Avatar
Joined: 2008-10-10
145 posts

Thank you so much for posting, a&w. I have another thread where I was running across several issues with the email class. This library simply dropped in and resolved all my issues. Thanks! I wonder if CI will release an updated file that resolves these issues you have apparently fixed…

 
Posted: 15 December 2008 02:55 PM   [ Ignore ]   [ # 5 ]   [ Rating: 0 ]
Joined: 2007-04-03
118 posts

Dunno. You are to first to reply/acknowledge my post. I figured I was doing something wrong.  I see a few people have downloaded the attachment, would have been nice if they would confirm the bug and say if the attached remedied the problem or not.

 
Posted: 16 December 2008 08:26 PM   [ Ignore ]   [ # 6 ]   [ Rating: 0 ]
Avatar
Joined: 2006-10-25
3 posts

I was having some weird email issues too, with the html message getting strangely garbled. This seems to have solved my problems. 

Nice job.

 
Posted: 20 June 2009 05:38 PM   [ Ignore ]   [ # 7 ]   [ Rating: 0 ]
Joined: 2009-02-25
1 posts

Your class solved my problems too, thanks a lot!

My clients were complaining about strange characters appearing in the message body (=3D and such). It so happened that the text/html part (in quoted-printable) was being printed as if it were an 8-bit encoded message.

 
Posted: 26 July 2009 07:32 AM   [ Ignore ]   [ # 8 ]   [ Rating: 0 ]
Joined: 2008-04-02
7 posts

Hi a&w,

Thanx for your code. I have replace CI Email class by your class. Now I am getting the following error :

A PHP Error was encountered

Severity
Notice

Message
fwrite() [function.fwrite]send of 11 bytes failed with errno=32 Broken pipe

Filename
libraries/Email.php

Line Number
1832

---------------------
etc 

and also shows the error :

451-The server has reached its limit for processing requests from your host451 Please try again later.

hello

The following SMTP error was encountered:
Unable to send dataAUTH LOGIN
Failed to send AUTH LOGIN command
Error:
Unable to send dataMAIL FROM:
from
The following SMTP error was encountered:
Unable to send dataRCPT TO:
to
The following SMTP error was encountered:
Unable to send dataDATA

data


--------------
etc 

your help would be appreciable

 
Posted: 04 September 2009 03:10 AM   [ Ignore ]   [ # 9 ]   [ Rating: 0 ]
Joined: 2008-04-02
7 posts

Hmm…I am not using CI Email class and switched to PHPMailer. Now everything works. I have followed the tutorial described here http://codeigniter.com/wiki/PHPMailer/

 
Posted: 22 June 2010 07:58 AM   [ Ignore ]   [ # 10 ]   [ Rating: 0 ]
Joined: 2008-09-26
12 posts

Hi a&w,
Thank you very much for the post. I too had similar problems with the email html text.
And once I replaced the changed-email-class of yours, it worked like a charm.

Thanks once again!

 
Posted: 29 September 2010 11:24 AM   [ Ignore ]   [ # 11 ]   [ Rating: 0 ]
Avatar
Joined: 2007-01-11
13 posts
a&w - 19 November 2008 07:31 PM

Here’s modified version based on above comments.


a&w - not even sure if you still frequent this thread… but!
you rawk! no, seriously…

MY BIGGER concern - as has been since i started using CI for the past 4 weeks, understanding, building, etc… is that when there is a SOLID solution like this…

***WHY OH WHY!!!!***
doesn’t it get looked at, integrated with, etc, into the latest releases of CI.

I spent **TOO** long dealing with this, for the past few days… as it relates to using html email and i read the wiki, read numerous resources, etc.. etc… and yet the header/alt boundary section you put into it CLEARLY fixed it all.

FYI - I’m using (for all who want to confirm):
CI 2.0
HVMC - with MS/E 5.3+
Ion_Auth (which is where i first ran into the html mail issue in part. - not the auth library itself)
php 5.3.3
os - windows vista
xampp

(yep, probably more than most want to know, but for me it helps and hopefully you’ll be helped too!)

my implementation of it was to (since using MS/Extensions + CI 2.0) override and add to the CI_Email by creating a library file:

for hoping to help with this thread… i’ll post in the next post what my MY_Email.php library file looks like.

I did this so as to keep the ‘core’ the core.

 
Posted: 29 September 2010 11:36 AM   [ Ignore ]   [ # 12 ]   [ Rating: 0 ]
Avatar
Joined: 2007-01-11
13 posts
/***
 *
 *  Created Library Extension of CI_Email using MY_Email
 *  based on a&w's work here:
 *  http://ellislab.com/forums/viewthread/97440/
 *
 **/
class MY_Email extends CI_Email {

    
// --------------------------------------------------------------------
    // below variable introduced from a&w's post taken from:
    // http://ellislab.com/forums/viewthread/97440/
    // --------------------------------------------------------------------

    
var $_alt_boundary "";    // used in hack/extension

    
function MY_Email($config = array( )) {
        parent
::CI_Email();
    
}


    
// --------------------------------------------------------------------
    // below functions added from a&w's post taken from:
    // http://ellislab.com/forums/viewthread/97440/
    // --------------------------------------------------------------------

    //new method for maintainability/consistency, etc.
    
function _get_content_type_header($type 'html'{
        
if ( $type == 'multi' {
            
return "Content-Type: multipart/alternative; boundary=\"".$this->_alt_boundary."\"".$this->newline;
        
}
        
return "Content-Type: text/".$type."; charset=".$this->charset.$this->newline;
    
}

    
//new method for maintainability/consistency, etc.
    
function _get_content_encoding_header($type 'data'{
        
if ( $type == 'quoted-printable' {
            
return "Content-Transfer-Encoding: quoted-printable";
        
}
        
return "Content-Transfer-Encoding: ".$this->_get_encoding();
    
}


        
// --------------------------------------------------------------------
        // below override function taken from:
        // http://ellislab.com/forums/viewthread/97440/
        // --------------------------------------------------------------------

    /**
     * Build Final Body and attachments
     * (modified as per above)
     *
     * @access    private
     * @return    void
     */
    
function _build_message() {
        
      
// for sake of space/speed - see:
      // thread: http://ellislab.com/forums/viewthread/97440/
      // to get the _build_message() function and put it here... 

    
}

}
/***
 *
 *  so ends MY_Email extension of CI_Email
 *  based on a&w's work here:
 *  http://ellislab.com/forums/viewthread/97440/
 *
 **/ 
 
Posted: 02 October 2012 05:33 PM   [ Ignore ]   [ # 13 ]   [ Rating: 0 ]
Avatar
Joined: 2009-12-18
49 posts

With php5.3, it has a built in quoted_printable_encode and _decode method.

You can overload this easily

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * CodeIgniter Email Class
 *
 * Permits email to be sent using Mail, Sendmail, or SMTP.
 *
 * @package  CodeIgniter
 * @subpackage Libraries
 * @category Libraries
 * @author  ExpressionEngine Dev Team
 * @link  http://ellislab.com/codeigniter/user-guide/libraries/email.html
 */
class MY_Email extends CI_Email {

 
/**
  * Prep Quoted Printable
  *
  * Prepares string for Quoted-Printable Content-Transfer-Encoding
  * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt
  *
  * Checks if quoted_printable_encode is a function and will use the built
  * in method in php 5.3, otherwise uses the current CI_Email version.
  * 
  * @access protected
  * @param string
  * @param integer
  * @return string
  */
 
protected function _prep_quoted_printable($str$charlim '')
 
{
  
if (function_exists("quoted_printable_encode")) {
   
return quoted_printable_encode($str);
  
else {   
   
return parent::_prep_quoted_printable($str,$charlim);
  
}
 }