]>
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
};
44 shift-
>{sock
}->close();
48 print {shift-
>{sock
}} @_, "\r\n";;
53 my ($self, $func, $data, $maxcount) = @_;
57 my $sock = $self->{sock
};
67 $self->reply ("500 5.5.1 Error: bad syntax");
70 ($cmd, $args) = split(/\s+/, $_, 2);
73 if ($cmd eq 'helo' || $cmd eq 'ehlo' || $cmd eq 'lhlo') {
76 $self->reply ("250-PIPELINING");
77 $self->reply ("250-ENHANCEDSTATUSCODES");
78 $self->reply ("250-8BITMIME");
79 $self->reply ("250-SMTPUTF8");
80 $self->reply ("250-XFORWARD NAME ADDR PROTO HELO");
81 $self->reply ("250 OK.");
82 $self->{lmtp
} = 1 if ($cmd eq 'lhlo');
84 } elsif ($cmd eq 'xforward') {
85 my @tmp = split (/\s+/, $args);
86 foreach my $attr (@tmp) {
87 my ($n, $v) = ($attr =~ /^(.*?)=(.*)$/);
88 $self->{xforward
}->{lc($n)} = $v;
90 $self->reply ("250 2.5.0 OK");
92 } elsif ($cmd eq 'noop') {
93 $self->reply ("250 2.5.0 OK");
95 } elsif ($cmd eq 'quit') {
96 $self->reply ("221 2.2.0 OK");
98 } elsif ($cmd eq 'rset') {
100 $self->reply ("250 2.5.0 OK");
102 } elsif ($cmd eq 'mail') {
103 if ($args =~ m/^from:\s*<([^\s\>]*)>([^>]*)$/i) {
105 my ($from, $opts) = ($1, $2);
106 if ($opts =~ m/\sSMTPUTF8/) {
107 $self->{smtputf8
} = 1;
108 $from = decode
('UTF-8', $from);
110 $self->{from
} = $from;
111 $self->reply ('250 2.5.0 OK');
114 $self->reply ("501 5.5.2 Syntax: MAIL FROM: <address>");
117 } elsif ($cmd eq 'rcpt') {
118 if ($args =~ m/^to:\s*<([^\s\>]+)>[^>]*$/i) {
119 my $to = $self->{smtputf8
} ? decode
('UTF-8', $1) : $1;
120 push @{$self->{to
}} , $to;
121 $self->reply ('250 2.5.0 OK');
124 $self->reply ("501 5.5.2 Syntax: RCPT TO: <address>");
127 } elsif ($cmd eq 'data') {
128 if ($self->save_data ()) {
129 eval { &$func ($data, $self); };
132 syslog
('err', $err);
135 my $cfg = $data->{pmg_cfg
};
138 foreach $a (@{$self->{to
}}) {
139 if ($self->{queue
}->{status
}->{$a} eq 'delivered') {
140 $self->reply ("250 2.5.0 OK ($self->{queue}->{logid})");
141 } elsif ($self->{queue
}->{status
}->{$a} eq 'blocked') {
142 if ($cfg->get('mail', 'ndr_on_block')) {
143 $self->reply ("554 5.7.1 Rejected for policy reasons ($self->{queue}->{logid})");
145 $self->reply ("250 2.7.0 BLOCKED ($self->{queue}->{logid})");
147 } elsif ($self->{queue
}->{status
}->{$a} eq 'error') {
148 my $code = $self->{queue
}->{status_code
}->{$a};
149 my $resp = substr($code, 0, 1);
150 my $mess = $self->{queue
}->{status_message
}->{$a};
151 $self->reply ("$code $resp.0.0 $mess");
153 $self->reply ("451 4.4.0 detected undelivered mail to <$a>");
157 my $queueid = $self->{queue
}->{logid
};
158 my $qstat = $self->{queue
}->{status
};
159 my @rec = keys %$qstat;
160 my @success_rec = grep { $qstat->{$_} eq 'delivered' } @rec;
161 my @reject_rec = grep { $qstat->{$_} eq 'blocked' } @rec;
163 if (scalar(@reject_rec) == scalar(@rec)) {
164 $self->reply ("554 5.7.1 Rejected for policy reasons ($queueid)");
165 syslog
('info', "reject mail $queueid");
166 } elsif ((scalar(@reject_rec) + scalar(@success_rec)) == scalar(@rec)) {
167 $self->reply ("250 2.5.0 OK ($queueid)");
168 if ($cfg->get('mail', 'ndr_on_block')) {
169 my $dnsinfo = $cfg->get_host_dns_info();
170 generate_ndr
($self->{from
}, [ @reject_rec ], $dnsinfo->{fqdn
}, $queueid) if scalar(@reject_rec);
173 $self->reply ("451 4.4.0 detected undelivered mail ($queueid)");
181 last if $count >= $maxcount;
182 last if $data->{errors
}; # abort if we find errors
186 $self->reply ("500 5.5.1 Error: unknown command");
189 $self->{sock
}->close;
197 if(!defined($self->{from
})) {
198 $self->reply ("503 5.5.1 Tell me who you are.");
202 if(!defined($self->{to
})) {
203 $self->reply ("503 5.5.1 Tell me who to send it.");
207 $self->reply ("354 End data with <CR><LF>.<CR><LF>");
209 my $sock = $self->{sock
};
214 $queue = PMG
::MailQueue-
>new ($self->{from
}, $self->{to
});
223 # RFC 2821 compliance.
228 print {$queue->{fh
}} $_;
229 $queue->{bytes
} += length ($_);
232 $queue->{fh
}->flush ();
234 $self->{queue
} = $queue;
237 syslog
('err', $err);
238 $self->reply ("451 4.5.0 Local delivery failed: $err");
241 if(!defined($done)) {
242 $self->reply ("451 4.5.0 Local delivery failed: unfinished data");
250 my ($sender, $receivers, $hostname, $queueid) = @_;
253 This is the mail system at host $hostname.
255 I'm sorry to have to inform you that your message could not
256 be delivered to one or more recipients.
258 For further assistance, please send mail to postmaster.
260 If you do so, please include this problem report.
263 554 5.7.1 Recipient address(es) rejected for policy reasons
266 my $ndr = MIME
::Entity-
>build(
267 Type
=> 'multipart/report; report-type=delivery-status;',
269 From
=> 'postmaster',
270 Subject
=> 'Undelivered Mail');
274 Type
=> 'text/plain; charset=utf-8',
277 my $delivery_status = <<EOF
278 Reporting-MTA: dns; $hostname
279 X-Proxmox-Queue-ID: $queueid
280 X-Proxmox-Sender: rfc822; $sender
283 foreach my $rec (@$receivers) {
284 $delivery_status .= <<EOF
285 Final-Recipient: rfc822; $rec
286 Original-Recipient: rfc822;$rec
289 Diagnostic-Code: smtp; 554 5.7.1 Recipient address rejected for policy reasons
295 Data
=> $delivery_status,
296 Type
=> 'message/delivery-status',
298 Description
=> 'Delivery report');
300 my $qid = PMG
::Utils
::reinject_mail
($ndr, '', [$sender], undef, $hostname);
302 syslog
('info', "sent NDR for rejecting recipients - $qid");
304 syslog
('err', "sending NDR for rejecting recipients failed");