Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision a40f0c2f

Von Martin Helmling martin.helmling@octosoft.eu vor etwa 7 Jahren hinzugefügt

  • ID a40f0c2f7523a7d6936ca483901c22dfe86358c9
  • Vorgänger bd4debfb
  • Nachfolger 58c266ea

Dateimanagement: Alle Anhänge per E-Mail versendbar machen

Es können an eine E-Mail alle Anhänge eines Dokumentes,
sowie die Anhänge am Kunden/Liefranten sowie die Anhänge an Artikeln
mitgesendet werden.

Falls ein Dokument bereits existiert muss es nicht noch neu erzeugt werden.

Als MIME Types werden die bereits in der Datenbank abgespeicherten Typen verwendet.

Es werden in Perl nun MIME::Entity und MIME::Parser verwendet,
deshalb ist der installationcheck erweitet.

Unterschiede anzeigen:

SL/Mailer.pm
24 24
package Mailer;
25 25

  
26 26
use Email::Address;
27
use Email::MIME::Creator;
27
use MIME::Entity;
28
use MIME::Parser;
29
use File::MimeInfo::Magic;
28 30
use File::Slurp;
29 31
use List::UtilsBy qw(bundle_by);
30 32

  
......
32 34
use SL::DB::EmailJournal;
33 35
use SL::DB::EmailJournalAttachment;
34 36
use SL::DB::Employee;
35
use SL::MIME;
36 37
use SL::Template;
37 38

  
38 39
use strict;
40
use Encode;
39 41

  
40 42
my $num_sent = 0;
43
my $parser;
41 44

  
42 45
my %mail_delivery_modules = (
43 46
  sendmail => 'SL::Mailer::Sendmail',
......
47 50
sub new {
48 51
  my ($type, %params) = @_;
49 52
  my $self = { %params };
53
  $parser = new MIME::Parser;
54
  $parser->output_under("users");
50 55

  
51 56
  bless $self, $type;
52 57
}
......
117 122
        $addr_obj->phrase($phrase);
118 123
      }
119 124

  
120
      push @header_addresses, $addr_obj->format;
125
      push @header_addresses, encode('MIME-Header',$addr_obj->format);
121 126
    }
122 127

  
123 128
    push @{ $self->{headers} }, ( ucfirst($item) => join(', ', @header_addresses) ) if @header_addresses;
......
128 133
  my ($self, $attachment) = @_;
129 134

  
130 135
  my %attributes = (
131
    disposition  => 'attachment',
132
    encoding     => 'base64',
136
    Disposition  => 'attachment',
137
    Encoding     => 'base64',
133 138
  );
134 139

  
140
  my $file_id = 0;
135 141
  my $attachment_content;
142
  my $email_journal = $::instance_conf->get_email_journal;
136 143

  
144
  $main::lxdebug->message(LXDebug->DEBUG2(), "mail5 att=".$attachment." email_journal=". $email_journal." id=".$attachment->{id});
137 145
  if (ref($attachment) eq "HASH") {
138
    $attributes{filename} = $attachment->{name};
139
    $attachment_content   = $attachment->{content} // eval { read_file($attachment->{filename}) };
146
    $attributes{Path}     = $attachment->{path} || $attachment->{filename};
147
    $attributes{Filename} = $attachment->{name};
148
    $file_id              = $attachment->{id}   || '0';
149
    $attributes{Type}     = $attachment->{type} || 'application/pdf';
150
    $attachment_content   = eval { read_file($attachment->{path}) } if $email_journal > 1;
140 151

  
141 152
  } else {
142 153
    # strip path
143
    $attributes{filename} =  $attachment;
144
    $attributes{filename} =~ s:.*\Q$self->{fileid}\E:: if $self->{fileid};
145
    $attributes{filename} =~ s:.*/::g;
146
    $attachment_content   =  eval { read_file($attachment) };
154
    $attributes{Path}     =  $attachment;
155
    $attributes{Filename} =  $attachment;
156
    $attributes{Filename} =~ s:.*\Q$self->{fileid}\E:: if $self->{fileid};
157
    $attributes{Filename} =~ s:.*/::g;
158

  
159
    my $application     = ($attachment =~ /(^\w+$)|\.(html|text|txt|sql)$/) ? 'text' : 'application';
160
    $attributes{Type}   = File::MimeInfo::Magic::magic($attachment);
161
    $attributes{Type} ||= "${application}/$self->{format}" if $self->{format};
162
    $attributes{Type} ||= 'application/octet-stream';
163
    $attachment_content = eval { read_file($attachment) } if $email_journal > 1;
147 164
  }
148 165

  
149
  return undef if !defined $attachment_content;
166
  return undef if $email_journal > 1 && !defined $attachment_content;
167
  $attachment_content ||= ' ';
168
  $main::lxdebug->message(LXDebug->DEBUG2(), "mail6 mtype=".$attributes{Type}." path=".
169
                            $attributes{Path}." filename=".$attributes{Filename});
150 170

  
151
  my $application             = ($attachment =~ /(^\w+$)|\.(html|text|txt|sql)$/) ? 'text' : 'application';
152
  $attributes{content_type}   = SL::MIME->mime_type_from_ext($attributes{filename});
153
  $attributes{content_type} ||= "${application}/$self->{format}" if $self->{format};
154
  $attributes{content_type} ||= 'application/octet-stream';
155
  $attributes{charset}        = $self->{charset} if lc $application eq 'text' && $self->{charset};
171
# $attributes{Charset}  = $self->{charset} if lc $application eq 'text' && $self->{charset};
172
  $attributes{Charset}  = $self->{charset} if $self->{charset};
156 173

  
157
  return Email::MIME->create(
158
    attributes => \%attributes,
159
    body       => $attachment_content,
174
  my $ent;
175
  if ( $attributes{Type} eq 'message/rfc822' ) {
176
    my $fh = IO::File->new($attributes{Path}, "r");
177
    if (! defined $fh) {
178
      return undef;
179
    }
180
    $ent = $parser->parse($fh);
181
    undef $fh;
182
    my $head = $ent->head;
183
    $head->replace('Content-disposition','attachment; filename='.$attributes{Filename});
184
  } else {
185
    $ent = MIME::Entity->build(%attributes);
186
  }
187
  push @{ $self->{mail_attachments}} , SL::DB::EmailJournalAttachment->new(
188
    name      => $attributes{Filename},
189
    mime_type => $attributes{Type},
190
    content   => ( $email_journal > 1 ? $attachment_content : ' '),
191
    file_id   => $file_id,
160 192
  );
193
  return $ent;
161 194
}
162 195

  
163 196
sub _create_message {
164 197
  my ($self) = @_;
165 198

  
166
  my @parts;
167

  
199
  push @{ $self->{headers} }, ('Type'    =>"multipart/mixed" );
200
  my  $top = MIME::Entity->build(@{$self->{headers}});
168 201
  if ($self->{message}) {
169
    push @parts, Email::MIME->create(
170
      attributes => {
171
        content_type => $self->{contenttype},
172
        charset      => $self->{charset},
173
        encoding     => 'quoted-printable',
174
      },
175
      body_str => $self->{message},
176
    );
177

  
178
    push @{ $self->{headers} }, (
179
      'Content-Type' => qq|$self->{contenttype}; charset="$self->{charset}"|,
180
    );
202
    $top->attach(Data => encode($self->{charset},$self->{message}),
203
                 Charset => $self->{charset},
204
                 Type => $self->{contenttype},
205
                 Encoding    => 'quoted-printable');
181 206
  }
182 207

  
183
  push @parts, grep { $_ } map { $self->_create_attachment_part($_) } @{ $self->{attachments} || [] };
184

  
185
  return Email::MIME->create(
186
    header_str => $self->{headers},
187
    parts      => \@parts,
188
  );
208
  map { $top->add_part($self->_create_attachment_part($_)) } @{ $self->{attachments} || [] };
209
  return $top;
189 210
}
190 211

  
191 212
sub send {
......
202 223
  $self->{charset}       =  'UTF-8';
203 224
  $self->{contenttype} ||=  "text/plain";
204 225
  $self->{headers}       =  [
205
    Subject              => $self->{subject},
226
    Subject              => encode('MIME-Header',$self->{subject}),
206 227
    'Message-ID'         => '<' . $self->_create_message_id . '>',
207 228
    'X-Mailer'           => "kivitendo $self->{version}",
208 229
  ];
230
  $self->{mail_attachments} = [];
231
  $self->{content_by_name}  = $::instance_conf->get_email_journal == 1 && $::instance_conf->get_doc_files;
209 232

  
210 233
  my $error;
211 234
  my $ok = eval {
......
215 238

  
216 239
    my $email = $self->_create_message;
217 240

  
218
    # $::lxdebug->message(0, "message: " . $email->as_string);
241
    #$::lxdebug->message(0, "message: " . $email->as_string);
219 242
    # return "boom";
220 243

  
221
    $self->{driver}->start_mail(from => $self->{from}, to => [ $self->_all_recipients ]);
244
    $self->{driver}->start_mail(from => encode('MIME-Header',$self->{from}), to => [ $self->_all_recipients ]);
222 245
    $self->{driver}->print($email->as_string);
223 246
    $self->{driver}->send;
224 247

  
......
227 250

  
228 251
  $error = $@ if !$ok;
229 252

  
230
  $self->_store_in_journal;
253
  $self->{journalentry} = $self->_store_in_journal;
254
  $parser->filer->purge;
231 255

  
232 256
  return $ok ? '' : "send email: $error";
233 257
}
234 258

  
235 259
sub _all_recipients {
236 260
  my ($self) = @_;
237

  
238 261
  $self->{addresses} ||= {};
239 262
  return map { @{ $self->{addresses}->{$_} || [] } } qw(to cc bcc);
240 263
}
......
251 274
  $extended_status //= $self->{driver}->extended_status if $self->{driver};
252 275
  $extended_status //= 'unknown error';
253 276

  
254
  my @attachments;
255

  
256
  @attachments = grep { $_ } map {
257
    my $part = $self->_create_attachment_part($_);
258
    if ($part) {
259
      SL::DB::EmailJournalAttachment->new(
260
        name      => $part->filename,
261
        mime_type => $part->content_type,
262
        content   => $part->body,
263
      )
264
    }
265
  } @{ $self->{attachments} || [] } if $journal_enable > 1;
266

  
267 277
  my $headers = join "\r\n", (bundle_by { join(': ', @_) } 2, @{ $self->{headers} || [] });
268 278

  
269
  SL::DB::EmailJournal->new(
279
  my $jentry = SL::DB::EmailJournal->new(
270 280
    sender          => SL::DB::Manager::Employee->current,
271 281
    from            => $self->{from}    // '',
272 282
    recipients      => join(', ', $self->_all_recipients),
......
274 284
    headers         => $headers,
275 285
    body            => $self->{message} // '',
276 286
    sent_on         => DateTime->now_local,
277
    attachments     => \@attachments,
287
    attachments     => \@{ $self->{mail_attachments} },
278 288
    status          => $status,
279 289
    extended_status => $extended_status,
280 290
  )->save;
291
  return $jentry->id;
281 292
}
282 293

  
283 294
1;

Auch abrufbar als: Unified diff