Analog has asked for the wisdom of the Perl Monks concerning the following question:

Folks, I'm having a tough time trying to get MIME::Lite to always sent both a HTML and TEXT email (so the client will always have something to display) and optionally have a attachment.

Here is pretty much what I have

my $message = MIME::Lite->build ( From =>'someemail, To=>'anotheremail, Subject=>'somesubject', Type =>'multipart/alternative' ); if ('i have a attachment') { $message->replace(Type => 'multipart/mixed'); $message->attach( Type=> 'AUTO', Path=> $upload_file, Filename=>$basename, Disposition => 'attachment' ); } $message->attach(Type=> 'TEXT', Data=> $text ); $message->attach(Type=> 'text/html', Data=> $html ); $message->send('smtp','000.000.000.000',Debug=>1,Timeout=>60,Port=> +26);

Currently with the above I always get a HTML/Text, but not the attachment. If I create/build the MIME::Lite object with "multipart/mixed", I will get the attachment but only the text version comes through (and the HTML is a 2nd attachment). It doesn't seem to matter how I create the MIME::Lite object (using new or build)

I feel like I just missing something stupid, but I have no idea what.

Any ideas? TIA!

Replies are listed 'Best First'.
Re: MIME::Lite and Multipart
by zwon (Abbot) on Sep 29, 2009 at 19:04 UTC

    If you want to have text and html versions of the message then you should combine them in mutipart/alternative. If you want to add an attachment then you should create multipart/mixed which would contain multipart/alternative with text and html, and attachment. So message structure should be as follows:

    multipart/mixed - multipart/alternative - text/plain - text/html - application/pdf or whatever you want
    Here's the small example that shows how to create such message:
    use strict; use warnings; use MIME::Lite; my $alternative = MIME::Lite->new( Type => 'multipart/alternative', ); $alternative->attach( Type => 'TEXT', Data => 'Message text', ); $alternative->attach( Type => 'text/html', Data => '<p><b>Message text</b></p>', ); my $message = MIME::Lite->new( Type => 'multipart/mixed', From => 'sender@example.com', To => 'rcpt@example.com', Subject => 'Example', ); $message->attach($alternative); $message->attach( Type => 'TEXT', Filename => 'passwd', Disposition => 'attachment', Path => '/etc/passwd', ); $message->print(\*STDOUT);
      Thanks zwon, I haven't tried it yet but that seems to make a little more sense.

      I still don't understand why the "Type" can't be added by itself. Even in your example I need to know if there is a attachment before I create the "my $message" :Lite object right?

        Yes, you should know if there's attachment, because if there's no attachment you should create only one MIME::Lite object (multipart/alternative message) and there's no need to create $message at all.

        I still don't understand why the "Type" can't be added by itself.

        Just a note before forwarding you to perldoc, the module source code and zwon for further study:

        you correctly wrote in the opener: $message->replace(Type=>'multipart/mixed');, and this indeed **works** and changes the mail structure you set with the Type=>... assignment during ->new/->build.

        Without an explicite Type, Dumper shows a non-MIME text/plain message. Adding mime parts seems to turn the original body (that you never defined in the opener or Re^4) into our undefined problem mime part, while also turning the Type to multipart/mixed. If my assumption is correct, just setting Data=>"" (and never setting a Type at all) before adding attachments should also avoid the undef bugs.

      Dear Deacon, I think he already had pretty much the same skeleton down pat and thus deserves help beyond pure rtfm and rtfm+keyword levels.

      He managed to stumble twice upon bugs that could be triggered by undef (both of which he might have avoided by exactly sticking to the skeleton), but I'd argue that triggering those bugs actually demonstrated some understanding and skill. Which is what we want to cultivate beyond copy/pasting boilerplate code.

        he already had pretty much the same skeleton down pat and thus deserves help beyond rtfm keyword level.

        Take another look onto my code and compare it with Analog's code. It's not about MIME::Lite usage and bugs in his code, it's about structure of resulting message.

Re: MIME::Lite and Multipart
by jakobi (Pilgrim) on Sep 29, 2009 at 15:48 UTC

    Your code obviously fails due to a lack of use MIME::Lite, some quotes, and assignments to the variables $text, $html, $upload_file, and optionally also $basename.

    Add those and the mails created do look pretty normal to me in mutt.

    Btw 1: don't forget to test-run the truncated example before posting - just a quick change before posting is a nice way to add errors!

    Btw 2: if your if('...attachment...') is intentional, add a comment. Otherwise an if(1) is more readable.

      Sorry, I was just trying to make it readable. I've found the problem is simply I can't set the "Type=>xxx" after the object is created, whenever I try I simply get "no data in this part" and if I set it and try to update it after using "add" or "replace", it doesn't change. I have things working but I have to create the MIME::Lite object each time for each type I want to send (instead of being able to build it as I go).

        Hmm. I kind of ignored the 'no data', as I HAD PROPER data/mails and no errors as soon as I had your scrap working with the bits you omitted.

        below is postfix' impression of 2 runs of your code

        Sep 29 17:39:15 anuurn postfix/smtpd[18818]: connect from localhost[12 +7.0.0.1] Sep 29 17:39:15 anuurn postfix/smtpd[18818]: 5B1D9404F6: client=localh +ost[127.0.0.1] Sep 29 17:39:15 anuurn postfix/smtpd[18818]: lost connection after DAT +A (506 bytes) from localhost[127.0.0.1] Sep 29 17:39:15 anuurn postfix/smtpd[18818]: disconnect from localhost +[127.0.0.1] Sep 29 17:39:15 anuurn postfix/cleanup[18821]: 5B1D9404F6: message-id= +<20090929153915.5B1D9404F6@anuurn.compact> Sep 29 17:39:53 anuurn postfix/smtpd[18818]: connect from localhost[12 +7.0.0.1] Sep 29 17:39:53 anuurn postfix/smtpd[18818]: A5E45404F6: client=localh +ost[127.0.0.1] Sep 29 17:39:53 anuurn postfix/smtpd[18818]: lost connection after DAT +A (506 bytes) from localhost[127.0.0.1] Sep 29 17:39:53 anuurn postfix/smtpd[18818]: disconnect from localhost +[127.0.0.1] Sep 29 17:39:53 anuurn postfix/cleanup[18821]: A5E45404F6: message-id= +<20090929153953.A5E45404F6@anuurn.compact>

        update META: keeping this one in <pre> intentionally; or is the line-broken version really preferrable even for non-code illustration not intended for use/reuse?? -> there's a nice profile setting to not wrap code lines on viewing. Less pain for me. (And you, if you've similar profile settings).

        Actually this doesn't happen, if you comment out the attachment block: it sends a proper email.

        With the attachement code, you see some debug output and the 'no data' at the very point my postfix reports loss of connection. What happens is that ::Lite happily emits a mail header, blank line and possibly the text and html variable content as mime parts (you did set them, right?). Which are the first 500 or so bytes of the partial message.

        However, ::Lite doesn't check in advance that it can create a proper email and it is NOW ::Lite aborts IF THE ATTACHEMENT FILE doesn't exist(?) or is undef(your scrap!). Which is what postfix is unhappy about and thus postfix rejects the already received partial mail as well.

        So with the variables being undef, I of course did never see a mail nor the exact problem scenario you have. With the missing bits added all I see is proper mails and no problems at all.

        Summary: use strict; use warnings; use diagnostics; would have pinpointed the trouble for both of us: the undefined (or not found?) $upload_file among others, which lead to your 'no data' observation. Also testing the rc of the send operation would have made the issue more obvious.

        needless to say, I also did the mistake to test the code w/o the use strict; ...