]>
git.proxmox.com Git - pmg-api.git/blob - src/PMG/SMTP.pm
15 my($this, $sock) = @_;
17 my $class = ref($this) || $this;
19 die("undefined socket: ERROR") if !defined($sock);
22 $self->{sock
} = $sock;
23 $self->{lmtp
} = undef;
28 $self->reply ("220 Proxmox SMTP Ready.");
35 $self->{from
} = undef;
37 $self->{queue
} = undef;
38 delete $self->{smtputf8
};
39 delete $self->{xforward
};
40 delete $self->{status
};
41 delete $self->{param
};
45 shift-
>{sock
}->close();
49 print {shift-
>{sock
}} @_, "\r\n";;
54 my ($self, $func, $data, $maxcount) = @_;
58 my $sock = $self->{sock
};
68 $self->reply ("500 5.5.1 Error: bad syntax");
71 ($cmd, $args) = split(/\s+/, $_, 2);
74 if ($cmd eq 'helo' || $cmd eq 'ehlo' || $cmd eq 'lhlo') {
77 $self->reply ("250-PIPELINING");
78 $self->reply ("250-ENHANCEDSTATUSCODES");
79 $self->reply ("250-8BITMIME");
80 $self->reply ("250-SMTPUTF8");
81 $self->reply ("250-DSN");
82 $self->reply ("250-XFORWARD NAME ADDR PROTO HELO");
83 $self->reply ("250 OK.");
84 $self->{lmtp
} = 1 if ($cmd eq 'lhlo');
86 } elsif ($cmd eq 'xforward') {
87 my @tmp = split (/\s+/, $args);
88 foreach my $attr (@tmp) {
89 my ($n, $v) = ($attr =~ /^(.*?)=(.*)$/);
90 $self->{xforward
}->{lc($n)} = $v;
92 $self->reply ("250 2.5.0 OK");
94 } elsif ($cmd eq 'noop') {
95 $self->reply ("250 2.5.0 OK");
97 } elsif ($cmd eq 'quit') {
98 $self->reply ("221 2.2.0 OK");
100 } elsif ($cmd eq 'rset') {
102 $self->reply ("250 2.5.0 OK");
104 } elsif ($cmd eq 'mail') {
105 if ($args =~ m/^from:\s*<([^\s\>]*?)>( .*)?$/i) {
107 my ($from, $opts) = ($1, $2 // '');
109 for my $opt (split(' ', $opts)) {
110 if ($opt =~ /(ret|envid)=([^ =]+)/i ) {
111 $self->{param
}->{mail
}->{$1} = $2;
112 } elsif ($opt =~ m/smtputf8/i) {
113 $self->{smtputf8
} = 1;
114 $self->{param
}->{mail
}->{smtputf8
} = 1;
115 $from = decode
('UTF-8', $from);
117 #ignore everything else
120 $self->{from
} = $from;
121 $self->reply ('250 2.5.0 OK');
124 $self->reply ("501 5.5.2 Syntax: MAIL FROM: <address>");
127 } elsif ($cmd eq 'rcpt') {
128 if ($args =~ m/^to:\s*<([^\s\>]+?)>( .*)?$/i) {
129 my $to = $self->{smtputf8
} ? decode
('UTF-8', $1) : $1;
131 push @{$self->{to
}} , $to;
132 for my $opt (split(' ', $opts)) {
133 if ($opt =~ /(notify|orcpt)=([^ =]+)/i ) {
134 $self->{param
}->{rcpt
}->{$to}->{$1} = $2;
136 #ignore everything else
139 $self->reply ('250 2.5.0 OK');
142 $self->reply ("501 5.5.2 Syntax: RCPT TO: <address>");
145 } elsif ($cmd eq 'data') {
146 if ($self->save_data ()) {
147 eval { &$func ($data, $self); };
150 syslog
('err', $err);
153 my $cfg = $data->{pmg_cfg
};
156 foreach $a (@{$self->{to
}}) {
157 if ($self->{queue
}->{status
}->{$a} eq 'delivered') {
158 $self->reply ("250 2.5.0 OK ($self->{queue}->{logid})");
159 } elsif ($self->{queue
}->{status
}->{$a} eq 'blocked') {
160 if ($cfg->get('mail', 'ndr_on_block')) {
161 $self->reply ("554 5.7.1 Rejected for policy reasons ($self->{queue}->{logid})");
163 $self->reply ("250 2.7.0 BLOCKED ($self->{queue}->{logid})");
165 } elsif ($self->{queue
}->{status
}->{$a} eq 'error') {
166 my $code = $self->{queue
}->{status_code
}->{$a};
167 my $resp = substr($code, 0, 1);
168 my $mess = $self->{queue
}->{status_message
}->{$a};
169 $self->reply ("$code $resp.0.0 $mess");
171 $self->reply ("451 4.4.0 detected undelivered mail to <$a>");
175 my $queueid = $self->{queue
}->{logid
};
176 my $qstat = $self->{queue
}->{status
};
177 my @rec = keys %$qstat;
178 my @success_rec = grep { $qstat->{$_} eq 'delivered' } @rec;
179 my @reject_rec = grep { $qstat->{$_} eq 'blocked' } @rec;
181 if (scalar(@reject_rec) == scalar(@rec)) {
182 $self->reply ("554 5.7.1 Rejected for policy reasons ($queueid)");
183 syslog
('info', "reject mail $queueid");
184 } elsif ((scalar(@reject_rec) + scalar(@success_rec)) == scalar(@rec)) {
185 $self->reply ("250 2.5.0 OK ($queueid)");
186 if ($cfg->get('mail', 'ndr_on_block')) {
187 my $dnsinfo = $cfg->get_host_dns_info();
188 generate_ndr
($self->{from
}, [ @reject_rec ], $dnsinfo->{fqdn
}, $queueid) if scalar(@reject_rec);
191 $self->reply ("451 4.4.0 detected undelivered mail ($queueid)");
199 last if $count >= $maxcount;
200 last if $data->{errors
}; # abort if we find errors
204 $self->reply ("500 5.5.1 Error: unknown command");
207 $self->{sock
}->close;
215 if(!defined($self->{from
})) {
216 $self->reply ("503 5.5.1 Tell me who you are.");
220 if(!defined($self->{to
})) {
221 $self->reply ("503 5.5.1 Tell me who to send it.");
225 $self->reply ("354 End data with <CR><LF>.<CR><LF>");
227 my $sock = $self->{sock
};
232 $queue = PMG
::MailQueue-
>new ($self->{from
}, $self->{to
});
241 # RFC 2821 compliance.
246 print {$queue->{fh
}} $_;
247 $queue->{bytes
} += length ($_);
250 $queue->{fh
}->flush ();
252 $self->{queue
} = $queue;
255 syslog
('err', $err);
256 $self->reply ("451 4.5.0 Local delivery failed: $err");
259 if(!defined($done)) {
260 $self->reply ("451 4.5.0 Local delivery failed: unfinished data");
268 my ($sender, $receivers, $hostname, $queueid) = @_;
271 This is the mail system at host $hostname.
273 I'm sorry to have to inform you that your message could not
274 be delivered to one or more recipients.
276 For further assistance, please send mail to postmaster.
278 If you do so, please include this problem report.
281 554 5.7.1 Recipient address(es) rejected for policy reasons
284 my $ndr = MIME
::Entity-
>build(
285 Type
=> 'multipart/report; report-type=delivery-status;',
287 From
=> 'postmaster',
288 Subject
=> 'Undelivered Mail');
292 Type
=> 'text/plain; charset=utf-8',
295 my $delivery_status = <<EOF
296 Reporting-MTA: dns; $hostname
297 X-Proxmox-Queue-ID: $queueid
298 X-Proxmox-Sender: rfc822; $sender
301 foreach my $rec (@$receivers) {
302 $delivery_status .= <<EOF
303 Final-Recipient: rfc822; $rec
304 Original-Recipient: rfc822;$rec
307 Diagnostic-Code: smtp; 554 5.7.1 Recipient address rejected for policy reasons
313 Data
=> $delivery_status,
314 Type
=> 'message/delivery-status',
316 Description
=> 'Delivery report');
318 my $qid = PMG
::Utils
::reinject_local_mail
($ndr, '', [$sender], undef, $hostname);
320 syslog
('info', "sent NDR for rejecting recipients - $qid");
322 syslog
('err', "sending NDR for rejecting recipients failed");