家èšãã©ã®ããã«ç®¡çããã®ã§ããïŒ
ç¹ã«ãã¹ãŠã®è³Œå ¥ãã¯ã¬ãžããã«ãŒãã§è¡ãããå Žåã¯ç¹ã«ãäºç®ãæ£ç¢ºã«è¿œè·¡ããããšã¯åžžã«å°é£ã§ããã çç±ã¯ç°¡åã§ã-ããªãã®ç®ã®åã«åŸã ã«æžå°ããŠãããéã®æããããŸããããããŠããæç¹ã§ããªãã¯ãã以äžäœ¿ãããšã¯äœããªãããšãç解ããŸãã è³Œå ¥ã®å€§éšåãã¯ã¬ãžããã«ãŒãã§æ¯æãããŠããå Žåãæ®ã£ãŠããéé¡ãŸãã¯äœ¿çšãããŠããéé¡ã確èªããå¯äžã®æ¹æ³ã¯ãã€ã³ã¿ãŒããããã³ã¯ãŸãã¯ã¢ãã€ã«ãã³ã¯ã«è¡ãããMintãªã©ã®éèã¢ã°ãªã²ãŒã¿ãŒã䜿çšããããšã§ãã å¯èœã§ãããèŠåŸãå¿ èŠã§ãããåãã«ãŒãããæ¯æãã ãã§ãªããããã確ç«ããããšã¯å°é£ã§ãã
ç§ã¯ãä»æãŸã ã©ãã ãã®ãéããããã«ã€ããŠã®éç¥ãæ¯æ¥åãåã£ããããã®ãªãã·ã§ã³ã«æºè¶³ãããšæããŸããã ã€ãŸããç§ã¯1ãæã®äºç®ãèšå®ããäœããç§ã®æ¯åºãã«ãŠã³ãããæ¯æ¥äºç®ã®ç¶æ ã«é¢ããã¬ããŒããéä¿¡ããŸãã
æãæãããªãªãã·ã§ã³ã¯ãéè¡APIã䜿çšãããããããã¬ã¹ãã©ãŠã¶ã䜿çšããŠããã°ã©ã ã§ã€ã³ã¿ãŒãããéè¡ã«ã¢ã¯ã»ã¹ããããšã§ãã æ®å¿µãªãããç§ã®éè¡ã®APIãžã®ã¢ã¯ã»ã¹ã¯ææã§ããã2èŠçŽ èªèšŒã®ããã«ã€ã³ã¿ãŒãããéè¡ãžã®ã¢ã¯ã»ã¹ã«ã¯åé¡ããããŸãã ãã ããå¥ã®ãªãã·ã§ã³ããããŸãã çŸåšãã»ãŒãã¹ãŠã®éè¡ãåãã©ã³ã¶ã¯ã·ã§ã³ã«å¯ŸããŠã¢ã©ãŒããéä¿¡ãããã©ã³ã¶ã¯ã·ã§ã³ãå®äºããææãéãå Žæãéç¥ããŠããŸãã ããã¯ãäºç®ãç¶æããããã«å¿ èŠãªæ å ±ã§ãã ãããã©ã®ããã«æ±ãããç解ããããšã¯æ®ã£ãŠããŸãã
éè¡ã¯æºåž¯é»è©±ãšã¡ãŒã«ã«ã¢ã©ãŒããéä¿¡ã§ããŸãã SMSã¡ãã»ãŒãžã®åŠçãè€éã§ãããããæºåž¯é»è©±ã®ãªãã·ã§ã³ã¯èæ ®ãããŸããã§ããã é»åã¡ãŒã«ã®ãªãã·ã§ã³ãéåžžã«é åçã§ãé»åã¡ãŒã«ã®ãœãããŠã§ã¢åŠçã¯æ°å幎åã«è¡ãããå¯èœæ§ããããŸãã ããããä»ã§ã¯èªå® ã«ããã©ããããããæã£ãŠããã ãã§ãåžžã«ãªã³ã«ãªã£ãŠããããã§ã¯ãããŸãããã€ãŸããAWSãªã©ãã¯ã©ãŠãã®ã©ããã§äºç®ãèªååããŸãã
AWSã«ã¯äœãå¿ èŠã§ããïŒ
AWSã«ã¯å€ãã®ãµãŒãã¹ããããŸãããå¿ èŠãªã®ã¯æ¬¡ã®3ã€ã ãã§ããEã¡ãŒã«ã®éåä¿¡-SESããããã®åŠç-Lambdaãããã³DynamoDBã®çµæã®ä¿åã ããã«ããã³ãã«ã®è£å©çãªãã®-SNSãKinesisãCloudWatchã ãããå¯äžã®ã¡ãã»ãŒãžåŠçãªãã·ã§ã³ã§ã¯ãããŸããïŒLambdaã®ä»£ããã«ãRDSïŒMySQLãPostgreSQLãOracleãªã©ïŒã«ããŒã¿ãä¿åã§ããDynamoDBã®ä»£ããã«EC2ã䜿çšã§ããŸãããŸããçç ãšBerkleyDBã®å°ããªãµãŒããŒã«ç°¡åãªã¹ã¯ãªãããæžãããšãã§ããŸãã
äžè¬çã«ããã¹ãŠã®åŠçã¯ã©ã®ããã«èŠããŸããïŒ ååŒéç¥ãå±ããæ¥ä»ãéé¡ãæ¯æãå ŽæãããŒã¿ããŒã¹ã«èšé²ãã1æ¥ã«1åãä»æã®æ®é«ãèšèŒããéç¥ãéä¿¡ããŸãã ã¢ãŒããã¯ãã£å šäœã¯ããå°ãè€éã§ã次ã®ããã«ãªããŸãã
- æçŽã¯SESã«å±ããŸãã
- SESã¯ãSNSãããã¯ã«é»åã¡ãŒã«ãéä¿¡ããŸãã
- Lambdaé¢æ°ProcessChargeã¯ãSNSãä»ããŠã¬ã¿ãŒãåä¿¡ãããšèµ·åãããã¬ã¿ãŒã解æããŠããã©ã³ã¶ã¯ã·ã§ã³ããŒã¿ãDynamoDB TransactionsããŒãã«ã«æžã蟌ã¿ãŸãã
- Lambdaé¢æ°UpdateSummaryã¯ãTransactionsããŒãã«ãžã®æžã蟌ã¿åŸã«ããªã¬ãŒãšããŠæ©èœããSummaryããŒãã«ã®äºç®ã®çŸåšã®ç¶æ ã«é¢ããããŒã¿ãæŽæ°ããŸãã
ãããã®æé ããã詳现ã«æ€èšããŠãã ããã
ã¡ãŒã«ãåãåã
SESãšãåŒã°ããã·ã³ãã«ãªã¡ãŒã«ãµãŒãã¹ã¯ãæçŽãéåä¿¡ããããã®ãµãŒãã¹ã§ãã ã¬ã¿ãŒãåä¿¡ããããå®è¡ããã¢ã¯ã·ã§ã³ãæå®ã§ããŸããS3ã«ã¬ã¿ãŒãä¿åããLambdaé¢æ°ãåŒã³åºããSNSãªã©ã«ã¬ã¿ãŒãéä¿¡ããŸãã æçŽãåãåãã«ã¯ããã¡ã€ã³ããã€ã³ãããå¿ èŠããããŸããã€ãŸããMXãã¡ã€ã³ã¬ã³ãŒãã§SESãµãŒããŒãæå®ããå¿ èŠããããŸãã åœæã¯èªåã®ãã¡ã€ã³ãæã£ãŠããªãã£ãã®ã§ããããå¥ã®AWSãµãŒãã¹Route 53ã䜿çšããŠç»é²ããæ£åœãªçç±ã§ãããšå€æããŸãããåãå ŽæãRoute 53ã§ããã¹ãããŸããã
ãã¡ã€ã³ãSESã«ãã€ã³ãããå Žåããã®æ€èšŒãå¿ èŠã§ãã ãããè¡ãããã«ãSESã¯DNSãŸãŒã³ïŒMXããã³TXTïŒã«ããã€ãã®ã¬ã³ãŒããè¿œå ããããã«èŠæ±ãããããã®ååšã確èªããŸãã ãã¡ã€ã³ãRoute 53ã§ãã¹ããããŠããå Žåãããã¯ãã¹ãŠèªåçã«è¡ãããŸãã ãã¡ã€ã³ãæ€èšŒãããããã¡ãŒã«åä¿¡ã®ã«ãŒã«ã®æ§æã«é²ãããšãã§ããŸãã ç§ã®å¯äžã®ã«ãŒã«ã¯éåžžã«åçŽã§ãïŒãã¡ã€ã³ã®ccalert @ã¢ãã¬ã¹ã«ãã¹ãŠã®æåãSNSã®ccalertsãããã¯ã«éä¿¡ããŸãã
aws> ses describe-receipt-rule --rule-set-name "ccalerts" --rule-name "ccalert" { "Rule": { "Name": "ccalert", "Recipients": [ "ccalert@=censored=â ], "Enabled": true, "ScanEnabled": true, "Actions": [ { "SNSAction": { "TopicArn": "arn:aws:sns:us-west-2:=censored=:ccalerts", "Encoding": "UTF-8" } } ], "TlsPolicy": "Optional" } }
ã¬ã¿ãŒåŠç
SNSãããã¯ã§æ°ããã¬ã¿ãŒãå ¬éããããšãLambdaé¢æ°ProcessChargeãåŒã³åºãããŸãã 圌女ã¯2ã€ã®ããšãè¡ãå¿ èŠããããŸããæçŽã解æããããŒã¿ããŒã¹ã«ããŒã¿ãä¿åããŸãã
from __future__ import print_function import json import re import uuid from datetime import datetime import boto3 def lambda_handler(event, context): message = json.loads(event['Records'][0]['Sns']['Message']) print("Processing email {}".format(message['mail'])) content = message['content'] trn = parse_content(content) if trn is not None: print("Transaction: %s" % trn) process_transaction(trn)
parse_contentïŒïŒã¡ãœããã¯è§£æãæ åœããŸãïŒ
def parse_content(content): content = content.replace("=\r\n", "") match = re.search(r'A charge of \(\$USD\) (\d+\.\d+) at (.+?) has been authorized on (\d+/\d+/\d+ \d+:\d+:\d+ \S{2} \S+?)\.', content, re.M) if match: print("Matched %s" % match.group(0)) date = match.group(3) # replace time zone with hour offset because Python can't parse it date = date.replace("EDT", "-0400") date = date.replace("EST", "-0500") dt = datetime.strptime(date, "%m/%d/%Y %I:%M:%S %p %z") return {'billed': match.group(1), 'merchant': match.group(2), 'datetime': dt.isoformat()} else: print("Didn't match") return None
ãã®äžã§ãäžå¿ èŠãªæåãåé€ããæ£èŠè¡šçŸã䜿çšããŠãã¡ãã»ãŒãžã«ãã©ã³ã¶ã¯ã·ã§ã³ã«é¢ããæ å ±ãå«ãŸããŠãããã©ããã確èªããå«ãŸããŠããå Žåã¯ãããæçã«åå²ããŸãã ç®çã®ããã¹ãã¯æ¬¡ã®ãšããã§ãã
Amazon.comã§ã®100.00ãã«ïŒ$ USDïŒã®è«æ±ã¯ã2017幎7æ19æ¥1:55:52 PM EDTã«æ¿èªãããŸããã
æ®å¿µãªãããPythonæšæºã©ã€ãã©ãªã¯ã¿ã€ã ãŸãŒã³ãã»ãšãã©èªèããŠããªããããEDTïŒæ±éšå€æéïŒã¯ãã®äžã«ã¯å«ãŸããŠããŸããã ãããã£ãŠãEDTãæ°å€æå®-0400ã«çœ®ãæããã¡ã€ã³ã¿ã€ã ãŸãŒã³ESTã«å¯ŸããŠãåãããšãè¡ããŸãã ãã®åŸããã©ã³ã¶ã¯ã·ã§ã³ã®æ¥ä»ãšæå»ã解æããDynamoDBã§ãµããŒããããæšæºISO 8601圢åŒã«å€æã§ããŸãã
ãã®ã¡ãœããã¯ããã©ã³ã¶ã¯ã·ã§ã³éãã¹ãã¢åãããã³æ¥ä»ãå«ãããã·ã¥ããŒãã«ãè¿ããŸãã ãã®ããŒã¿ã¯ãprocess_transactionã¡ãœããã«æž¡ãããŸãã
def process_transaction(trn): ddb = boto3.client('dynamodb') trn_id = uuid.uuid4().hex ddb.put_item( TableName='Transactions', Item={ 'id': {'S': trn_id}, 'datetime': {'S': trn['datetime']}, 'merchant': {'S': trn['merchant']}, 'billed': {'N': trn['billed']} })
ãã®äžã§ãTransactionsããŒãã«ã«ããŒã¿ãä¿åããäžæã®ãã©ã³ã¶ã¯ã·ã§ã³èå¥åãçæããŸãã
äºç®ã®æŽæ°
ããã§ããã詳现ã«ãã€ãŸããäºç®ã®ç¶æ ãã©ã®ããã«ç£èŠãããŠããã®ãã詳ãã説æããŸãã ããã€ãã®å€ãèªåã§å®çŸ©ããŸãã
- äºç®-ãã®æã®äºç®ã®å€§ããã
- åèš-æãããã®æ¯åºé¡ã
- å©çšå¯èœ-æ®ããïŒäºç®-åèšïŒ;
ãã€ã§ããããããã¹ãŠã®å€ãç¥ãããã§ãã ãããè¡ãã«ã¯2ã€ã®æ¹æ³ããããŸãã
- äºç®ã®ç¶æ ãç¥ãå¿ èŠããããã³ã«ããã©ã³ã¶ã¯ã·ã§ã³ãåèšãããŠåèšãååŸãããå©çšå¯èœ=ïŒäºç®-åèšïŒã«ãªããŸãã
- æ°ãããã©ã³ã¶ã¯ã·ã§ã³ãèšé²ããããã³ã«ãåèšãæŽæ°ãããŸãã äºç®ã®ç¶æ ã調ã¹ãå¿ èŠãããå Žåãavailable =ïŒbudget-totalïŒãå®è¡ãããŸãã
ã©ã¡ãã®ã¢ãããŒãã«ãé·æãšçæããããéžæã¯ã·ã¹ãã ã®èŠä»¶ãšå¶éã«å€§ããäŸåããŸãã æåã®ã¢ãããŒãã¯ãããŒã¿ãéæ£èŠåããããã©ã³ã¶ã¯ã·ã§ã³éãåå¥ã«ä¿åãããšããç¹ã§åªããŠããŸãã äžæ¹ãåèšã¯ãªã¯ãšã¹ãããšã«èæ ®ãããå¿ èŠããããŸãã ç§ã®ããªã¥ãŒã ã§ã¯ããã¯åé¡ã«ãªããŸããããç§ã®å Žåã¯DynamoDBã«ããå¶éããããŸãã Nåã®ãã©ã³ã¶ã¯ã·ã§ã³ã®åèšãèšç®ããã«ã¯ãNåã®ã¬ã³ãŒããèªã¿åãå¿ èŠããããŸããã€ãŸããNåã®èªã¿åããã£ãã·ãã£ãŒãŠãããã䜿çšããŸãã æããã«ãããã¯éåžžã«ã¹ã±ãŒã©ãã«ãªãœãªã¥ãŒã·ã§ã³ã§ã¯ãªããæ°åã®ãã©ã³ã¶ã¯ã·ã§ã³ã§ãå°é£ïŒãŸãã¯é«ã³ã¹ãïŒãåŒãèµ·ãããŸãã
2çªç®ã®ã¢ãããŒãã䜿çšãããšãåèšã¯åãã©ã³ã¶ã¯ã·ã§ã³ã®åŸã«æŽæ°ãããåžžã«ææ°ã®ç¶æ ã«ãªããŸããããã«ããããã¹ãŠã®ãã©ã³ã¶ã¯ã·ã§ã³ã®åèšãåé¿ãããŸãã ç§ã®å Žåããã®ã¢ãããŒãã¯ããåççã§ããããã«æããŸããã å床ãããŸããŸãªæ¹æ³ã§å®è£ ããŸãã
- ProcessChargeã®åãLambdaé¢æ°ã§åãã©ã³ã¶ã¯ã·ã§ã³ãèšé²ããåŸãåèšãæŽæ°ããŸãã
- TransactionsããŒãã«ã«æ°ããèŠçŽ ãè¿œå ããåŸãããªã¬ãŒã®åèšãæŽæ°ããŸãã
ãã«ãã¹ã¬ããã®èŠ³ç¹ãå«ããããªã¬ãŒã§ã®æŽæ°ã¯ããå®çšçã§ãããããLambdaé¢æ°UpdateSummaryãäœæããŸããã
from __future__ import print_function from datetime import datetime import boto3 def lambda_handler(event, context): for record in event['Records']: if record['eventName'] != 'INSERT': print("Unsupported event {}".format(record)) return trn = record['dynamodb']['NewImage'] print(trn) process_transaction(trn)
ããŒãã«ã«èŠçŽ ãè¿œå ããã€ãã³ãã®ã¿ã«é¢å¿ããããä»ã®ãã¹ãŠã¯ç¡èŠãããŸãã
def process_transaction(trn): period = get_period(trn) if period is None: return billed = trn['billed']['N'] # update total for current period update_total(period, billed) print("Transaction processed")
process_transactionïŒïŒã§ããã©ã³ã¶ã¯ã·ã§ã³ãå±ãã幎æã®åœ¢åŒã§æéãèšç®ããæŽæ°ã¡ãœããã®åèšãåŒã³åºããŸãã
def get_period(trn): try: # python cannot parse -04:00, it needs -0400 dt = trn['datetime']['S'].replace("-04:00", "-0400") dt = dt.replace("-05:00", "-0500") dt = dt.replace("-07:00", "-0700") dt = datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S%z") return dt.strftime("%Y-%m") except ValueError as err: print("Cannot parse date {}: {}".format(trn['datetime']['S'], err)) return None
ãã®ã³ãŒãã¯å®ç§ãšã¯ã»ã©é ããã®ã§ãPythonã®èå³æ·±ãæ©èœã圹å²ãæãããŸãããISO8601æšæºã«æºæ ããPythonèªäœãçæãã-HHïŒMM圢åŒã®ã¿ã€ã ãŸãŒã³ãæã€æ¥ä»/æå»ã解æã§ããŸããïŒäžèšã®ã³ãŒããparse_contentïŒïŒïŒã¡ãœããå ã ãããã£ãŠãå¿ èŠãªã¿ã€ã ãŸãŒã³ãã圌ãç解ããŠãã-HHMM圢åŒã«çœ®ãæããã ãã§ãã ãµãŒãããŒãã£ã®ã©ã€ãã©ãªã䜿çšããŠãããçŸããããããšãå¯èœã§ãããå°æ¥ã®ããã«æ®ããŠããããšãã§ããŸããã ãããããç§ã®Pythonã®è²§åŒ±ãªç¥èããŸã 圱é¿ãäžããŠãã-ãã®ãããžã§ã¯ãã¯ãPythonã§ã®æåã®éçºçµéšã§ãã
åèšæŽæ°ïŒ
def update_total(period, billed): ddb = boto3.client('dynamodb') response = load_summary(ddb, period) print("Summary: {}".format(response)) if 'Item' not in response: create_summary(ddb, period, billed) else: total = response['Item']['total']['N'] update_summary(ddb, period, total, billed)
ãã®ã¡ãœããã§ã¯ãload_summaryïŒïŒã¡ãœããã䜿çšããŠçŸåšã®æéã®æŠèŠãèªã¿èŸŒã¿ãŸãããã®ã¡ãœããã§ã¯ãåèšãæŽæ°ããå¿ èŠããããŸãã èŠçŽããŸã ååšããªãå Žåã¯ãcreate_summaryïŒïŒã¡ãœããã§äœæããååšããå Žåã¯update_summaryïŒïŒã§æŽæ°ããŸãã
def load_summary(ddb, period): print("Loading summary for period {}".format(period)) return ddb.get_item( TableName = 'Summary', Key = { 'period': {'S': period} }, ConsistentRead = True )
æ²ç€ºã®æŽæ°ã¯è€æ°ã®ã¹ã¬ããããè¡ãããšãã§ãããããäžè²«ããèªã¿åãã䜿çšããŸããããã¯ããé«äŸ¡ã§ãããæåŸã«èšé²ãããå€ãååŸããããšãä¿èšŒããŸãã
def create_summary(ddb, period, total): print("Creating summary for period {} with total {}".format(period, total)) ddb.put_item( TableName = 'Summary', Item = { 'period': {'S': period}, 'total': {'N': total}, 'budget': {'N': "0"} }, ConditionExpression = 'attribute_not_exists(period)' )
æ°ããã»ãã¥ãªãã£æ å ±ãäœæããå Žåãè€æ°ã®ã¹ããªãŒã ããèšé²ã§ããã®ãšåãçç±ã§ãæ¡ä»¶ä»ãã¬ã³ãŒãConditionExpression = 'attribute_not_existsïŒperiodïŒ'ã䜿çšãããæ°ããã»ãã¥ãªãã£æ å ±ãååšããªãå Žåã«ã®ã¿ä¿åãããŸãã ãããã£ãŠãload_summaryïŒïŒã«ããŒãããããšãããšãã«ééå ã§èª°ããèŠçŽãäœæã§ããå Žåããããcreate_summaryïŒïŒã§äœæããããšãããšãput_itemïŒïŒã®åŒã³åºãã¯äŸå€ãšLambdaé¢æ°å šäœã§çµäºããŸãåèµ·åãããŸãã
def update_summary(ddb, period, total, billed): print("Updating summary for period {} with total {} for billed {}".format(period, total, billed)) ddb.update_item( TableName = 'Summary', Key = { 'period': {'S': period} }, UpdateExpression = 'SET #total = #total + :billed', ConditionExpression = '#total = :total', ExpressionAttributeValues = { ':billed': {'N': billed}, ':total': {'N': total} }, # total is a reserved word so we create an alias #total to use it in expression ExpressionAttributeNames = { '#total': 'total' } )
ãµããªãŒã®åèšå€ã®æŽæ°ã¯ãDynamoDBå ã§è¡ãããŸãã
UpdateExpression = 'SET #total = #total +ïŒè«æ±æžã¿'
ã»ãšãã©ã®å Žåãããã¯ã»ãã¥ãªãã£ã§ä¿è·ãããæŽæ°ã«ã¯ååã§ãããæ§ããã«è¡åããããšã決å®ããèŠçŽãå¥ã®ã¹ã¬ããã§æŽæ°ãããªãã£ãå Žåã«ã®ã¿èšé²ãè¡ããããšããæ¡ä»¶ãè¿œå ããŸããã
ConditionExpression = '#total =ïŒtotal'ã
totalã¯DynamoDBã®ããŒã¯ãŒãã§ãããããDynamoDBåŒã§äœ¿çšããã«ã¯ãã·ããã ãäœæããå¿ èŠããããŸãã
ExpressionAttributeNames = {
ã#totalãïŒãtotalã
}
ããã«ããããã©ã³ã¶ã¯ã·ã§ã³ã®åŠçãšäºç®ã®æŽæ°ã®ããã»ã¹ãå®äºããŸãã
æé | äºç® | åèš |
---|---|---|
2017-07 | 1000 | 500 |
äºç®éç¥
ã·ã¹ãã ã®æåŸã®éšåã¯ãäºç®ã®ç¶æ ã®éç¥ã§ãã åé ã§æžããããã«ãç§ã¯1æ¥ã«1åéç¥ãåãåãã ãã§ååã§ãã ãã ããåãã©ã³ã¶ã¯ã·ã§ã³ã®åŸããŸãã¯è²»çš/æ®é«ã®ãããå€ã®åŸã«éç¥ããããšã劚ãããã®ã¯äœããããŸããã éç¥ã¡ãŒã«ãéä¿¡ããããã®ã¢ãŒããã¯ãã£ã¯éåžžã«ã·ã³ãã«ã§ã次ã®ããã«ãªããŸãã
- CloudWatchã¿ã€ããŒã¯1æ¥ã«1åå®è¡ãããDailyNotification Lambdaé¢æ°ãåŒã³åºããŸãã
- DailyNotificationã¯ãDynamoDBãµããªãŒããŒãã«ããããŒã¿ãããŒãããSESãåŒã³åºããŠé»åã¡ãŒã«ãéä¿¡ããŸãã
from __future__ import print_function from datetime import date import boto3 def lambda_handler(event, context): ddb = boto3.client('dynamodb') current_date = date.today() print("Preparing daily notification for {}".format(current_date.isoformat())) period = current_date.strftime("%Y-%m") response = load_summary(ddb, period) print("Summary: {}".format(response)) if 'Item' not in response: print("No summary available for period {}".format(period)) return summary = response['Item'] total = summary['total']['N'] budget = summary['budget']['N'] send_email(total, budget) def load_summary(ddb, period): print("Loading summary for period {}".format(period)) return ddb.get_item( TableName = 'Summary', Key = { 'period': {'S': period} }, ConsistentRead = True )
æåã«ãçŸåšã®æéã®æŠèŠãããŠã³ããŒãããããšããŸããæŠèŠããªãå Žåã¯ãäœæ¥ãçµäºããŸãã ããå Žåãç§ãã¡ã¯æçŽãæºåããŠéä¿¡ããŸãïŒ
def send_email(total, budget): sender = "Our Budget <ccalert@==censored==>" recipients = [â==censored==â] charset = "UTF-8" available = float(budget) - float(total) today = date.today().strftime("%Y-%m-%d") message = ''' As of {0}, available funds are ${1:.2f}. This month budget is ${2:.2f}, spendings so far totals ${3:.2f}. More details coming soon!''' subject = "How are we doing?" textbody = message.format(today, float(available), float(budget), float(total)) print("Sending email: {}".format(textbody)) client = boto3.client('ses', region_name = 'us-west-2') try: response = client.send_email( Destination = { 'ToAddresses': recipients }, Message = { 'Body': { 'Text': { 'Charset': charset, 'Data': textbody, }, }, 'Subject': { 'Charset': charset, 'Data': subject, }, }, Source = sender, ) # Display an error if something goes wrong. except Exception as e: print("Couldn't send email: {}".format(e)) else: print("Email sent!")
ãŸãšã
ããã ãã§ã ããã§ãåãã©ã³ã¶ã¯ã·ã§ã³ã®åŸãåä¿¡ã¬ã¿ãŒãåŠçãããŠäºç®ãæŽæ°ããã1æ¥ã«1åãäºç®ã®ç¶æ ã«é¢ããéç¥ãšãšãã«ã¬ã¿ãŒãéä¿¡ãããŸãã ç§ã¯ãŸã æ©èœãè¿œå ããèšç»ããããŸããããšãã°ãã«ããŽãªå¥ã«è²»çšãåé¡ããéç¥ã«æè¿ã®ãã©ã³ã¶ã¯ã·ã§ã³ã®ãªã¹ããå«ããŸããäœã䟡å€ã®ããããšãèµ·ãã£ãããå¥ã®èšäºã§å ±æããŸãã ã質åãã³ã¡ã³ããç·šéãããå Žåã¯ãã³ã¡ã³ãããåŸ ã¡ããŠããŸãã