RSS Git Download  Clone
Raw Blame History
package Local::SendGrid;

use v5.34;

use Moo;
use IO::All;
use Data::Printer;
use Types::Standard qw(HashRef); # Str ArrayRef  Object
# for Email::Sendgrid::V3 ------------------------------------------------------
use Email::SendGrid::V3;
# for HTTP::Request/LWP::UserAgent ---------------------------------------------
use HTML::Make;
use LWP::UserAgent;
use HTTP::Request ();
use JSON::MaybeXS qw(encode_json);
# ------------------------------------------------------------------------------

has msg => ( is => 'ro', isa => HashRef, required => 1 );

# ZBOX Ubuntu 22.04 key:
my $api_key = io('/home/raj/.local/sendgrid_api_key')->slurp 
	|| die 'no api key'; # say $api_key;
# default e-mail to/from (requires separate 'chomp' - wtf???):
my $self_addr = io('/home/raj/.local/email_address')->slurp
	|| die 'no default email addess'; chomp($self_addr); # say $self_addr; exit;

# uses Email::SendGrid::V3 send() method, which uses HTTP::Tiny (https api url)
# does not output very useful errors
sub send {
	my $msg = shift->msg; # p $msg;
	
	$msg->{from} ||= $self_addr;
	$msg->{to}   ||= $self_addr;
	
	$msg->{subject} or die "missing subject line";
	grep $msg->{$_}, qw/html text/ or die "require text or html message";
	
	my $sg = Email::SendGrid::V3->new( api_key => $api_key )
		->from( $msg->{from} )
		->subject( $msg->{subject} )
		->add_content( 'text/plain', $msg->{text} )
		->add_envelope( to => [ $msg->{to} ] );
	# optional functions; sandbox tests message for compliance, does not send
	$sg->sandbox_mode(1) if $msg->{test_only};
	$sg->footer(1, %{ $msg->{footer} }) if $msg->{footer};
		# p $sg; return 0;
	my $result = $sg->send; # p $result;
	return $result->{success}
		? "Email success" : "Email failure: " . $result->{reason};
}

# manual message construction; uses HTTP::Request & LWP::UserAgent; constructs 
# same message data structure as Email::SendGrid::V3; outputs more userful errors
sub _send {
	my $msg = shift->msg; # p $msg;
	
	$msg->{from} ||= $self_addr;
	$msg->{to}   ||= $self_addr;

	my $ua  = LWP::UserAgent->new();
	# sendgrid api url:
	my $url = 'https://api.sendgrid.com/v3/mail/send';

	my $header = [
		'Content-Type' => 'application/json; charset=UTF-8',
		'Authorization' => "Bearer $api_key",
	];

	my %data = (
		from => { email => $msg->{from} },
		subject => $msg->{subject},
		content => [
			{
				type  => 'text/plain',
				value => $msg->{text},
			},
		],
 		personalizations => [
			{
				to => [ 
					{ email => $msg->{to} },
				],
			},
		],
	); # p %data; exit;
	
	# test_only mode ?
	$data{mail_settings}{sandbox_mode} = { enable => JSON::true } 
		if $msg->{test_only};
	
	# optional footer:
	if ( my $footer = $msg->{footer} ) {
		$data{mail_settings} ||= {}; # not strictly necessary
		$data{mail_settings}{footer} = {
			enable => JSON::true,
			text   => $footer->{text} || undef,
			html   => _format_html_footer( $footer->{html} ) || undef,
		}; # p $data{mail_settings};
	}
		 p %data;
	my $encoded_data = encode_json(\%data);

	my $req = HTTP::Request->new('POST', $url, $header, $encoded_data); # p $req; exit;
	my $res = $ua->request($req);  p $res;
	
	return $res->is_success 
		? 'Email success' : 'Email failure: ' . $res->status_line;
}

sub _format_html_footer {
	my $txt = shift || return; # optional

	my $obj = HTML::Make->new('footer');
	# $obj->add_attr(class => 'beano');
	$obj->add_text( $txt ); # say $obj->text;
	return $obj->text;
}

1;