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

Using mainly Send mail with attachment using only SMTP with some hints from Sending attachments in emails using SMTP here is what I have:
my $msg = "foo"; my $subj = get_datetime(); my $csvfile = "opnet_ace_cap_agent_audit_$subj.csv"; my $boundary = 'frontier'; my $smtp = Net::SMTP->new('smtp.somecorp.com', Timeout => 60); $smtp->mail( "root\@$hostname.somecorp.com" ); $smtp->to( @to); $smtp->data(); foreach my $dst ( @to ) { $smtp->datasend( "To: $dst\n" ) } # @to is a global (ducks for cover) $smtp->datasend("Subject: Opnet: Ace Capture Agent Audit: $subj\n"); $smtp->datasend("\n"); $smtp->datasend("Content-type: multipart/mixed; \n\tboundary=\"$bounda +ry\"\n"); $smtp->datasend("MIME-Version: 1.0\n"); $smtp->datasend("\n--$boundary\n"); $smtp->datasend("Content-type: text/plain\n"); $smtp->datasend("Content-Disposition: quoted-printable\n"); $smtp->datasend("\n$msg\n"); $smtp->datasend("--$boundary\n"); $smtp->datasend("Content-Type: application/text; name=\"$csvfile\"\n") +; $smtp->datasend("Content-Disposition: attachment; filename=\"$csvfile\ +"\n"); $smtp->datasend("\n"); $smtp->datasend(\@csv); # Global array (ducks for cover again). $smtp->datasend("--$boundary--\n"); $smtp->dataend(); $smtp->quit;
And this is what I am getting:
X-Message-Delivery: Vj0xLjE7dXM9MDtsPTE7YT0xO0Q9MTtTQ0w9MA== X-Message-Status: n:0 X-SID-PRA: root@nexus6.somecorp.com X-Message-Info: JGTYoYF78jHHuiSNiwoFu0whHwJgX/CsT9mqf3HC10h8SNpkHwOrgZ +mf4Gx8BxnSmZ+h/1ABqtNbvbB/F7nK1sjKX60rxMi2 Received: from smtp2.somecorp.com ([x.x.x.x]) by col0-mc4-f8.Col0.hotm +ail.com with Microsoft SMTPSVC(6.0.3790.3959); Fri, 26 Jun 2009 19:35:38 -0700 Received: from foo.somecorp.com ([x.x.x.x]) by smtp2.somecorp.com with + Microsoft SMTPSVC(6.0.3790.3959); Fri, 26 Jun 2009 21:35:38 -0500 X-TM-IMSS-Message-ID:<1ecc05ff0013bcbe@foo.somecorp.com> Received: from localhost.localdomain (x.x.x.x) by bar.somecorp.com (x.x.x.x) with Microsoft SMTP Server id x.x.x.x; Fri, 26 Jun 2009 21:35:36 -0500 To: <me@somecorp.com>, <me@msn.com> Subject: Opnet: Ace Capture Agent Audit: 2009_06_26_21-35-37 MIME-Version: 1.0 Content-Type: text/plain Message-ID: <de015822-96f4-435a-a299-95f70950d70a@bar.somecorp.com> From: <root@somecorp.com> Return-Path: root@comecorp.com Date: Fri, 26 Jun 2009 21:35:36 -0500 X-OriginalArrivalTime: 27 Jun 2009 02:35:38.0504 (UTC) FILETIME=[F4F3A +080:01C9F6CF] Content-type: multipart/mixed; boundary="frontier" MIME-Version: 1.0 --frontier Content-type: text/plain Content-Disposition: quoted-printable Fail ---- SOMEHOST SOMEHOST SOMEHOST Host Unreachable ---------------- thevoid Pass ---- SOMEHOST SOMEHOST SOMEHOST SOMEHOST SOMEHOST SOMEHOST --frontier Content-Type: application/text; name="opnet_ace_cap_agent_audit_2009_0 +6_26_21-35-37.csv" Content-Disposition: attachment; filename="opnet_ace_cap_agent_audit_2 +009_06_26_21-35-37.csv" rc,host,resolved_name,elapsed_time 1,SOMEHOST,x.x.x.x,0.0012669563293457 1,SOMEHOST,x.x.x.x,0.00101494789123535 1,SOMEHOST,x.x.x.x,0.00100302696228027 1,SOMEHOST,x.x.x.x,0.000874996185302734 0,SOMEHOST,x.x.x.x,5.00376486778259 0,SOMEHOST,x.x.x.x,5.00477504730225 1,SOMEHOST,x.x.x.x,0.00123500823974609 1,SOMEHOST,x.x.x.x,0.000978946685791016 0,SOMEHOST,x.x.x.x,0.00164794921875 undef,thevoid,undef,undef --frontier--

So the multipart stuff isn't making it through. Any ideas?

Using ActivePerl 5.10.0 on Solaris SPARC. And I need to use core modules. (>.<)

Update1: Just to be clear, the output is from a "View Message Source" via Microsoft Hotmail. So I am receiving the message, but the multipart is completely broken -- everything after the "X-OriginalArrivalTime" line is the body of the message!

Also, in the actual code I have an "|| die" for every $smtp-> line so I know they are not failing outright (Update3: sorry I forget to mention this). And the output from get_datetime looks like: "2009_06_26_21-35-37" (which can be seen in the output I pasted in).

In case it matters, the mail server I am sending this through is Exchange (I think Exchange 2007).

I'm not an expert on SMTP, MIME, etc. so my guess is I'm doing something wrong in that regard.

Update2: Solution: ig nails it in Re^3: Problems sending an email attachment using Net::SMTP. Thanks so much for the help!!!

Replies are listed 'Best First'.
Re: Problems sending an email attachment using Net::SMTP
by Anonymous Monk on Jun 27, 2009 at 04:20 UTC
    Have you considered using Mail::Sender instead? If all you need to do is send an attachment to a recipient, it's dead simple.
      Why is it that whenever someone says they need to use core modules someone always suggests a non-core module?

      Elda Taluta; Sarks Sark; Ark Arks

Re: Problems sending an email attachment using Net::SMTP
by ig (Vicar) on Jun 27, 2009 at 05:20 UTC

    I wonder what the value of $subj is and whether that is causing problems. You could check the return values of your calls to datasend to ensure they are succeeding.

    I tried on a default compile of perl 5.10.0 on CentOS 5, with $subj set to a simple string (as I didn't have your get_datetime()) and both the empty line after the Subject: header and the Content-type records were delivered.

      Did it come through with the CSV file as an attachment? The output I pasted in is from the email my hotmail account received (from the view message source option) so all of the text is making it through but the whole multipart aspect is broken.

      get_datetime() produces output like: 2009_06_26_21-35-37 so I don't think it would be causing a problem.

      Elda Taluta; Sarks Sark; Ark Arks

        With a little change, the CSV came through as an attachment.

        use strict; use warnings; use Net::SMTP; my $msg = "foo"; my $subj = "my test subject"; my $csvfile = "opnet_ace_cap_agent_audit_$subj.csv"; my $boundary = 'frontier'; my $hostname = "myhost"; my @to = ( "user\@localhost" ); my @csv = ( "one line of csv", "another line of csv", ); my $smtp = Net::SMTP->new('smtp.somecorp.com', Timeout => 60); $smtp->mail( "root\@$hostname.somecorp.com" ); $smtp->to( @to); $smtp->data(); foreach my $dst ( @to ) { $smtp->datasend( "To: $dst\n" ) } # @to is a global (ducks for cover) $smtp->datasend("Subject: Opnet: Ace Capture Agent Audit: $subj\n"); $smtp->datasend("MIME-Version: 1.0\n"); $smtp->datasend("Content-type: multipart/mixed; \n\tboundary=\"$bounda +ry\"\n"); $smtp->datasend("\n"); $smtp->datasend("--$boundary\n"); $smtp->datasend("Content-type: text/plain\n"); $smtp->datasend("Content-Disposition: quoted-printable\n"); $smtp->datasend("\n$msg\n"); $smtp->datasend("--$boundary\n"); $smtp->datasend("Content-Type: application/text; name=\"$csvfile\"\n") +; $smtp->datasend("Content-Disposition: attachment; filename=\"$csvfile\ +"\n"); $smtp->datasend("\n"); $smtp->datasend(\@csv); # Global array (ducks for cover again). $smtp->datasend("--$boundary--\n"); $smtp->dataend(); $smtp->quit;

        update: it's not very good CSV content, but it did come through as an attachment.