3 """Send emails through AWS SES. 5 Uses the AWS SES call send-mail. 6 Has the following parameters: 8 Body contents: (at least one of the following has to be specified.) 9 - text -- the plain text version of the email. 10 - html -- the HTML-formatted version of the email. 12 - subject -- the subject of the email. This is required. 13 - efrom -- the from email. This is required. 14 The efrom requires verification by AWS SES (either by email address or by domain.) 15 - replyto -- the reply to email. (submitform.pl & submitsecure.pl) 17 Email destinations: (at least one of the following has to be specified.) 18 Destinations are space-separated like a@comp.dom b@comp.dom ... 19 - to -- a list of to recipients. (Who the email is actually addressed to.) 20 - bcc -- a list of bcc recipients. (List isn't visible in email.) 21 - cc -- the cc for the email. (Visible list in email.) 23 Amazon requires the from email to be verified or the domain verified. 31 from botocore.exceptions
import ClientError
35 format=(
"[%(levelname)-5s] %(asctime)-15s ({}|%(funcName)s|%(lineno)d) " 36 ":: %(message)s").format(__file__)
37 LOGGER = logging.getLogger(__name__)
38 LOGGER.setLevel(logging.DEBUG)
39 logging_handler = logging.StreamHandler()
40 logging_handler.setFormatter(logging.Formatter(format))
41 LOGGER.addHandler(logging_handler)
44 USAGE_HELP = (
"Usage: sendSESEmail.py [-h] [--to TO [TO ...]]" 45 "[--bcc BCC [BCC ...]] [--cc CC [CC ...]] --efrom EFROM" 46 "[--replyto REPLYTO [REPLYTO ...]] --subject SUBJECT" 47 "[--plaintext PLAINTEXT] [--htmltext HTMLTEXT]" 48 "[--quiet] [--context CONTEXT]")
52 AWS_REGION = os.getenv(
'AWS_REGION',
'us-west-2')
56 """Custom ArgumentParser class 59 argparse.ArgumentParser 63 """Suppressing default error method 65 Return custom error message on ArgumentParser.error. 68 message -- error message 73 raise BaseException(message)
77 """Prepare argument parser. 80 parser -- ArgumentParser object 82 parser = CustomArgumentParser (
83 description =
"Send emails through AWS SES.",
84 formatter_class = argparse.RawDescriptionHelpFormatter,
85 epilog = textwrap.dedent(
'''\ 86 additional information: 87 One of --to, --bcc, or --cc has to be defined. 88 One of --plaintext or --htmltext has to be defined. 89 --efrom and --subject are required. 92 parser.add_argument (
"--to", nargs =
"+",
93 help =
"Space-separated list of to email addresses",
96 parser.add_argument (
"--bcc", nargs =
"+",
97 help =
"Space-separated list of bcc email addresses",
100 parser.add_argument (
"--cc", nargs =
"+",
101 help =
"Space-separated list of cc email addresses",
104 parser.add_argument (
"--efrom",
105 help =
"From email address",
108 parser.add_argument (
"--replyto", nargs =
"+",
109 help =
"Reply to email address",
112 parser.add_argument (
"--subject",
113 help =
"Subject of the email",
116 parser.add_argument (
"--plaintext",
117 help =
"Email body in plaintext",
120 parser.add_argument (
"--htmltext",
121 help =
"Html body in HTML",
124 parser.add_argument(
"--quiet", action =
"store_true",
125 help =
"Suppress success message",
128 parser.add_argument(
"--context",
129 help = (
"Json string for logging application" 130 "context for the email messages being sent."),
138 """Main method to execute operations on email verification. 141 argv {list} -- list of script arguments 152 'response': response,
160 args = parser.parse_args(argv)
161 mainReturn[
"context"] = args.context
164 if (args.to ==
None and args.bcc ==
None and args.cc ==
None):
165 raise BaseException (
"Destination has to be specified. One of" 166 " the --to, --bcc or --cc options need" 169 if (args.plaintext ==
None and args.htmltext ==
None):
170 raise BaseException (
"Email body has to be specified")
172 except (BaseException)
as e:
176 mainReturn[
"status"] = return_code
177 mainReturn[
"error"].append(USAGE_HELP)
178 mainReturn[
"error"].append(evalue)
179 LOGGER.error(json.dumps(mainReturn))
181 except (Exception)
as e:
183 mainReturn[
"status"] = return_code
184 mainReturn[
"error"] = e
185 LOGGER.error(json.dumps(mainReturn))
193 client = boto3.client(
'ses', region_name=AWS_REGION)
197 if (args.to !=
None):
198 destination[
"ToAddresses"] = args.to
199 if (args.bcc !=
None):
200 destination[
"BccAddresses"] = args.bcc
201 if (args.cc !=
None):
202 destination[
"CcAddresses"] = args.cc
207 message[
"Subject"] = {}
208 message[
"Subject"][
"Data"] = args.subject
209 message[
"Subject"][
"Charset"] = charset
210 if (args.plaintext !=
None):
212 message[
"Body"][
"Text"] = {}
213 message[
"Body"][
"Text"][
"Data"] = args.plaintext
214 message[
"Body"][
"Text"][
"Charset"] = charset
216 if (args.htmltext !=
None):
217 if "Body" not in message:
220 message[
"Body"][
"Html"] = {}
221 message[
"Body"][
"Html"][
"Data"] = args.htmltext
222 message[
"Body"][
"Html"][
"Charset"] = charset
224 if (args.replyto !=
None):
226 response = client.send_email (
228 Destination = destination,
230 ReplyToAddresses = args.replyto,
231 ConfigurationSetName=
'ses-detail-logging',
235 response = client.send_email (
237 Destination = destination,
239 ConfigurationSetName=
'ses-detail-logging',
242 except ClientError
as e:
244 mainReturn[
"status"] = return_code
245 mainReturn[
"error"] = str(e)
247 except Exception
as e:
249 mainReturn[
"status"] = return_code
250 mainReturn[
'error'] = str(e)
252 mainReturn[
'response'] = response
255 LOGGER.error(json.dumps(mainReturn))
257 LOGGER.info(json.dumps(mainReturn))
263 """Script entrypoint""" 264 sys.exit(
main(sys.argv[1:]))
267 if __name__ ==
"__main__":