Haineko

 view release on metacpan or  search on metacpan

lib/Haineko/Sendmail.pm  view on Meta::CPAN


                my $relayclass = q();       # (String) Class name of $smtpmailer
                my $smtpmailer = undef;     # (Haineko::SMTPD::Relay::*) Mailer object
                my $relayingto = undef;     # (Ref->Hash) Mailertable
                my $credential = undef;     # (Ref->Hash) Username and password for SMTP-AUTH or API

                $relayingto = $mailerconf->{'rcpt'}->{ $r->host } // $sendershub;
                $relayingto = $sendershub if $relayingto->{'disabled'};

                $relayingto = $defaulthub unless keys %$relayingto;
                $relayingto = $defaulthub if $relayingto->{'disabled'};

                $relayingto->{'port'}   //= 25;
                $relayingto->{'host'}   //= '127.0.0.1';
                $relayingto->{'mailer'} //= 'ESMTP';

                if( $relayingto->{'auth'} ) {
                    $credential = $autheninfo->{ $relayingto->{'auth'} } // {};
                } 
                $relayingto->{'auth'} = q() unless keys %$credential;

                if( $relayingto->{'mailer'} =~ m/\A(?:ESMTP|Haineko|MX)\z/ ) {
                    # Use Haineko::SMTPD::Relay::ESMTP or Haineko::SMTPD::Relay::Haineko
                    #   ::MX      = Directly connect to the host listed in MX Resource record
                    #   ::ESMTP   = Generic SMTP connection to an external server
                    #   ::Haineko = Relay an message to Haineko running on other host
                    my $methodargv = {
                        'ehlo'      => $serverconf->{'hostname'},
                        'mail'      => $submission->addresser->address,
                        'rcpt'      => $r->address,
                        'head'      => $mailheader,
                        'body'      => \$body,
                        'attr'      => $attributes,
                        'host'      => $relayingto->{'host'} // '127.0.0.1',
                        'retry'     => $relayingto->{'retry'} // 0,
                        'sleep'     => $relayingto->{'sleep'} // 5,
                        'timeout'   => $relayingto->{'timeout'} // 59,
                        'starttls'  => $relayingto->{'starttls'},
                    };

                    if( $relayingto->{'mailer'} eq 'ESMTP' ) {
                        # use well-known port for SMTP
                        $methodargv->{'port'} = $relayingto->{'port'} // 25;
                        $methodargv->{'debug'} = $relayingto->{'debug'} // 0;

                    } elsif( $relayingto->{'mailer'} eq 'Haineko' ) {
                        # Haineko uses 2794 by default
                        $methodargv->{'port'} = $relayingto->{'port'} // 2794;

                    } elsif( $relayingto->{'mailer'} eq 'MX' ) {
                        # Mail Exchanger is waiting on *:25
                        $methodargv->{'port'} = 25;
                        $methodargv->{'debug'} = $relayingto->{'debug'} // 0;
                    }

                    $relayclass = sprintf( "Haineko::SMTPD::Relay::%s", $relayingto->{'mailer'} );
                    Module::Load::load( $relayclass );
                    $smtpmailer = $relayclass->new( %$methodargv );

                    if( $relayingto->{'auth'} ) {
                        # Load credentials for SMTP-AUTH
                        $smtpmailer->auth( 1 );
                        $smtpmailer->username( $credential->{'username'} );
                        $smtpmailer->password( $credential->{'password'} );
                    }

                    $smtpmailer->sendmail();

                } elsif( $relayingto->{'mailer'} =~ m/(?:Discard|Screen)/ ) {
                    # These mailer does not open new connection to any host.
                    # Haineko::SMTPD::Relay::
                    #   - Discard: email blackhole. It will discard all messages
                    #   - Screen: print the email message to STDERR
                    $relayclass = sprintf( "Haineko::SMTPD::Relay::%s", $relayingto->{'mailer'} );
                    Module::Load::load( $relayclass );

                    my $methodargv = {
                        'ehlo'      => $serverconf->{'hostname'},
                        'mail'      => $submission->addresser->address,
                        'rcpt'      => $r->address,
                        'head'      => $mailheader,
                        'body'      => \$body,
                        'attr'      => $attributes,
                    };
                    $smtpmailer = $relayclass->new( %$methodargv );
                    $smtpmailer->sendmail();

                } elsif( $relayingto->{'mailer'} =~ m|\A/| or $relayingto->{'mailer'} eq 'File' ) {
                    # Haineko::SMTPD::Relay::File mailer
                    require Haineko::SMTPD::Relay::File;
                    my $mailfolder = $relayingto->{'mailer'} eq 'File' ? '/tmp' : $relayingto->{'mailer'};
                    my $methodargv = {
                        'ehlo'      => $serverconf->{'hostname'},
                        'host'      => $mailfolder,
                        'mail'      => $submission->addresser->address,
                        'rcpt'      => $r->address,
                        'head'      => $mailheader,
                        'body'      => \$body,
                        'attr'      => $attributes,
                    };
                    $smtpmailer = Haineko::SMTPD::Relay::File->new( %$methodargv );
                    $smtpmailer->sendmail();

                } else {
                    $mailheader->{'To'} = $r->address;
                    my $methodargv = {
                        'ehlo'    => $serverconf->{'hostname'},
                        'mail'    => $submission->addresser->address,
                        'rcpt'    => $r->address,
                        'head'    => $mailheader,
                        'body'    => \$body,
                        'attr'    => $attributes,
                        'retry'   => $relayingto->{'retry'} // 0,
                        'timeout' => $relayingto->{'timeout'} // 60,
                    };

                    if( length $relayingto->{'mailer'} ) {
                        # Use Haineko::SMTPD::Relay::* except H::S::R::ESMTP, 
                        # H::S::R::Haineko and H::S::R::Discard.
                        try {
                            $relayclass = sprintf( "Haineko::SMTPD::Relay::%s", $relayingto->{'mailer'} );
                            Module::Load::load( $relayclass );
                            $smtpmailer = $relayclass->new( %$methodargv );

                            if( $relayingto->{'auth'} ) {
                                # Load credentials for SMTP-AUTH
                                $smtpmailer->auth( 1 );
                                $smtpmailer->username( $credential->{'username'} );
                                $smtpmailer->password( $credential->{'password'} );
                            }

                            $smtpmailer->sendmail();

                            if( not $smtpmailer->response->dsn ) {
                                # D.S.N. is empty or undefined.
                                if( $smtpmailer->response->error ) {
                                    # Error but no D.S.N.
                                    $smtpmailer->response->dsn( '5.0.0' );
                                } else {
                                    # Successfully sent but no D.S.N.
                                    $smtpmailer->response->dsn( '2.0.0' );
                                }
                            }

                        } catch {
                            require Haineko::E;
                            my $v = [ split( "\n", $_ ) ]->[0];
                            my $E = Haineko::E->new( $v );
                            my $R = { 
                                'code' => 500, 
                                'error' => 1, 
                                'message' => [ $E->mesg->[0] ],
                            };

                            $smtpmailer = Haineko::SMTPD::Relay->new( %$methodargv );
                            $smtpmailer->response( Haineko::SMTPD::Response->new( %$R ) );
                        };

                    } else {
                        # The value of "mailer" is empty
                        $smtpmailer = Haineko::SMTPD::Relay->new( %$methodargv );
                        my $R = { 
                            'code' => 500, 
                            'error' => 1, 
                            'message' => [ 'The value of "mailer" is empty' ],
                        };
                        $smtpmailer->response( Haineko::SMTPD::Response->new( %$R ) );
                    }
                }

                if( $maxworkers > 1 ) {
                    # Send the received response as a JSON from child process
                    # to parent process via pipe.
                    my $p = $preforkipc->[ $thisworker ];
                    $p->writer;
                    print( { $p } Haineko::JSON->dumpjson( $smtpmailer->response->damn ) );
                    close $p;

                } else {
                    # Add the received response as a Haineko::SMTPD::Response object
                    # into Haineko::SMTPD::Session object.
                    $submission->add_response( $smtpmailer->response );
                }

            } # End of for(ONE_TO_ONE)



( run in 1.051 second using v1.01-cache-2.11-cpan-0bb4e1dffa6 )