Haineko

 view release on metacpan or  search on metacpan

lib/Haineko/SMTPD/Relay/AmazonSES.pm  view on Meta::CPAN


    for my $e ( @{ $self->{'head'}->{'Received'} } ) {
        # Convert email headers
        push @$headerlist, 'Received' => $e;
    }

    for my $e ( keys %{ $self->{'head'} } ) {
        # Make email headers except ``MIME-Version''
        next if $e eq 'MIME-Version';

        if( ref $self->{'head'}->{ $e } eq 'ARRAY' ) {
            # Such as Received: header
            for my $f ( @{ $self->{'head'}->{ $e } } ) {
                push @$headerlist, $e => $f;
            }

        } else { 
            push @$headerlist, $e => $self->{'head'}->{ $e };
        }
    }
    $methodargv->{'header'} = $headerlist;

    my $mimeobject = Email::MIME->create( %$methodargv );
    my $mailstring = MIME::Base64::encode_base64 $mimeobject->as_string;

    # http://docs.aws.amazon.com/ses/latest/DeveloperGuide/query-interface.html
    my $amazonses1 = sprintf( "https://%s/", SES_ENDPOINT );
    my $dateheader = gmtime;
    my $datestring = $dateheader->strftime;
    my $parameters = {
        'Action' => 'SendRawEmail',
        'Source' => $self->{'mail'},
        'RawMessage.Data' => $mailstring,
        'Destinations.member.1' => $self->{'rcpt'},
        'Timestamp' => $dateheader->datetime.'.000Z',
        'Version' => SES_APIVERSION,
    };

    # AWS3 AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE,Signature=lBP67vCvGlDMBQ=dofZxg8E8SUEXAMPLE,Algorithm=HmacSHA256,SignedHeaders=Date;Host
    my $headerkeys = [ 'AWSAccessKeyId', 'Signature', 'Algorithm' ];
    my $reqheaders = {
        'Date' => $datestring,
        'Host' => SES_ENDPOINT,
    };
    my $identifier = {
        'AWSAccessKeyId' => $self->{'username'},
        'Signature' => __PACKAGE__->sign( $reqheaders->{'Date'}, $self->{'password'} ),
        'Algorithm' => 'HmacSHA256',
        'SignedHeaders' => 'Date',
    };
    my $authheader = join( ', ', map { sprintf( "%s=%s", $_, $identifier->{ $_ } ) } @$headerkeys );


    $methodargv = { 
        'agent' => $self->{'ehlo'},
        'timeout' => $self->{'timeout'},
        'ssl_opts' => { 'SSL_verify_mode' => 0 },
        'headers' => [
            'date' => $datestring,
            'host' => SES_ENDPOINT,
            'content-type' => 'application/x-www-form-urlencoded',
            'if-ssl-cert-subject' => sprintf( "/CN=%s", SES_ENDPOINT ),
            'x-amzn-authorization' => sprintf( "AWS3-HTTPS %s", $authheader ),
        ],
    };
    my $httpclient = Furl->new( %$methodargv );
    my $htresponse = undef;
    my $retryuntil = $self->{'retry'} || 0;
    my $smtpstatus = 0;
    my $exceptions = 0;
    my $sendmailto = sub {
        $htresponse = $httpclient->post( $amazonses1, undef, $parameters );
        return 0 unless defined $htresponse;
        return 0 unless $htresponse->is_success;

        $smtpstatus = 1;
        return 1;
    };

    while(1) {
        last if $sendmailto->();
        last if $retryuntil == 0;

        $retryuntil--;
        sleep $self->{'sleep'};
    }

    if( defined $htresponse ) {
        # Check response from API
        my $htcontents = undef;
        my $htmimetype = $htresponse->content_type || q();
        my $nekoparams = { 
            'code'    => $htresponse->code,
            'host'    => SES_ENDPOINT,
            'port'    => 443,
            'rcpt'    => $self->{'rcpt'},
            'error'   => $htresponse->is_success ? 0 : 1,
            'mailer'  => 'AmazonSES',
            'message' => [ $htresponse->message ],
            'command' => 'POST',
        };

        if( $htmimetype eq 'text/xml' ) {
            # text/xml
            try { 
                require XML::Simple;

            } catch {
                # XML::Simple is not installed
                $nekoparams->{'error'} = 1;
                $nekoparams->{'message'} = [ 'Please install XML::Simple 2.20 or later' ];
                $exceptions = 1;
            };

            if( not $exceptions ) {
                # XML::Simple is already installed
                try {
                    # Amazon SES respond contents as a XML
                    $htcontents = XML::Simple::XMLin( $htresponse->content );

                    for my $e ( keys %{ $htcontents->{'Error'} } ) {



( run in 0.747 second using v1.01-cache-2.11-cpan-524268b4103 )