0

I have created static web site which I am planning to host in S3 bucket. This HTML has a form and attachment feature which will be sent to my email id when user will attach a file and hit 'Upload'. Below is my HTML code snippets -

<form enctype="multipart/form-data"  name="fileinfo">
            <label>Your email address:</label>
            <input id = "email "type="email" autocomplete="on" autofocus name="userid" placeholder="email" required size="32" maxlength="64" /><br />
            <label>Custom file label:</label>
            <input type="text" name="filelabel" size="12" maxlength="32" /><br />
            <label>File to stash:</label>
            <input type="file" name="file" id = "fileUpload" required />
             <input type="button" id = "upload" value="Upload!" />
        </form>​

and then Jquery to trigger POST request to AWS API gateway

$('#upload').on("click", function (){
  var oOutput = document.querySelector("div"),
      oData = new FormData(form);

    var xhttp = new XMLHttpRequest();

    xhttp.onreadystatechange = function() {
          if (this.readyState == 4 && this.status == 200) {
            // Typical action to be performed when the document is ready:
             console.log(xhttp.responseText);
            console.log(xhttp.statusText);
            console.log(xhttp.status);
            oOutput.innerHTML = xhttp.responseText;
            } else {
                oOutput.innerHTML = "Error " + xhttp.status + " occurred when trying to upload your file.<br \/>";
            }
          };

    xhttp.open("POST", "https://myLambdaAPIURL", true);
    xhttp.setRequestHeader("Content-type", "application/json;charset=UTF-8");
    xhttp.send(JSON.stringify({Email:$('#email').val(),fileUpload:$('#fileUpload').val()}));

API gateway in AWS has all the default configurations to process the json format.

My AWS lambda code which works fine to send just an email.

import smtplib , os
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.base import MIMEBase
from email.message import Message
from email.encoders import encode_base64
from email.mime.text import MIMEText
from mimetypes import guess_type


def lambda_handler(event, context):
    msg = MIMEMultipart()
    msg['Subject'] = 'File Uploaded'
    msg['From'] = 'user@gmail.com'
    msg['To'] = 'user@gmail.com'
    emailFrom = "user@gmail.com"
    emailTo ="user@gmail.com"

    for file in event['fileUpload']:
        mimetype, encoding = guess_type(file)
        if mimetype == None:
            mimetype = "text/plain"
        mimetype = mimetype.split('/',1)    
        fp = open(file, "rb")       
        attachment.set_payload(fp.read())
        fp.close()
        encode_base64(attachment)
        attachment.add_header('Content-Disposition', 'attachment', file=os.path.basename(file))
        msg.attach(attachment)
    s = smtplib.SMTP('smtp.gmail.com:587')
    s.starttls()
    s.login('user@gmail.com','password')
    response = s.sendmail(emailFrom, emailTo, msg.as_string())
    s.quit()

return response

But when I attach a file and try to process it, the fake path error comes

{"stackTrace": [["/var/task/pyLambda.py", 24, "lambda_handler", "fo = open(filename, \"rb\")"]], "errorType": "IOError", "errorMessage": "[Errno 2] No such file or directory: u'C:\\fakepath\\testing.txt'"}

so I am thinking may be I can use \tmp directory in AWS lambda but not sure how to do that.

Any help or any guidance is highly appreciated.

Dunedan
  • 5,560
  • 6
  • 29
  • 38
S_T
  • 43
  • 2
  • 10
  • 1
    Apparently the code above isn't the (complete) one, responsible for this error message. Please provide the real code, otherwise it's difficult/impossible to help you. – Dunedan Dec 17 '17 at 18:40
  • I have updated python code right after heading "Updated python code to send email with attachment". I got the attachment code from gitHub but I think it will not work in my scenario. Let me know what you think. – S_T Dec 18 '17 at 04:35

2 Answers2

0

What you're doing is submitting a POST-request to your AWS Lambda function which contains the file name of the file to upload. On AWS Lambda side you then try to open a file with that name.

You get an error message, because the file name is relative to the computer of the user sending the form and AWS Lambda has no knowledge about the path where the file is supposed to be at all.

What you might want to do is to change your Javascript code so it puts the file content (encoded as base64) into the JSON-body of the request and read that data in your AWS Lambda function. You then won't need to read a physical file on AWS Lambda side anymore, but instead just get the file content from the request.

How to upload file content with Javascript is covered by other questions, such as: JavaScript: Upload file

Dunedan
  • 5,560
  • 6
  • 29
  • 38
  • What I am trying now is I updated body template on Integration request as "multipart/form-data" and then tried to upload the file. The python lambdahandler function's event object received the file information but it is something like this -----WebKitFormBoundarykGHBkXoER9gNuVna\r\n Content-Disposition: form-data; name="fileUpload"; filename="Rendered.pdf" Content-Type: application/pdf ----encoded version of the pdf data ------. I would like to know if there is a way I can parse the file name and its content. – S_T Dec 21 '17 at 06:07
0
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from smtplib import SMTPException
import base64
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from operator import itemgetter
import json
import boto3
from smtplib import SMTPException
from email import encoders

def lambda_handler(event, context):
    msg = MIMEMultipart()
    email = event['from'] 
    password =event['password'] 
    msg['Subject'] = event["subject"]
    you = event["to"]
    body = event["message"]
    msg['From']=email
    msg['To']= ", ".join(you)
    if len(you) ==0 or email=="":
        return {
        'status': 'False',
       'statusCode': 400,
       'message': 'Email not sent, From or To cannot be blank'
      }
    msg.attach(MIMEText(body, 'plain'))
    if(len(event['files'])==len(event['attach_base64'])):
        for i in range(len(event['attach_base64'])):
            filename = event['files'][i]
            data = event['attach_base64'][i]
            data1 = data
            attach_file = base64.b64decode(data1)
            #msg.attach(MIMEText(body, "plain"))
            part = MIMEBase('application', 'octet-stream')
            part.set_payload(attach_file)
            #part.set_payload(attach_file)
            encoders.encode_base64(part)
             #encoders.encode_base64(part)

            part.add_header(
                    "Content-Disposition",
                    "decoded_data; filename=%s" % filename)
            msg.attach(part)
    else:
        return {
        'status': 'False',
       'statusCode': 400,
       'message': 'Missing filename OR base64 of some file'
      }

    if event["message"] =="" and event["subject"] =="" and len(event['files'])==0 and len(event['attach_base64'])==0 :
        return {
        'status': 'False',
       'statusCode': 400,
       'message': 'Email cannot be blank'
      }

    try:
        smtpObj = smtplib.SMTP(host='smtp.gmail.com', port=587)
        smtpObj.starttls()
        smtpObj.login(email,password)
        smtpObj.sendmail(email, you, msg.as_string())
        print("in try --------------------------------------->")
        smtpObj.quit()
    except smtplib.SMTPException as e:
        print ("Error: unable to send email due to",e)
        error_msg = "Error: unable to send email due to "
        error_msg = error_msg + str(e)
        return {
        'status': 'False',
       'statusCode': 417,
       'body': error_msg
      }

    return {
        'status': 'True',
       'statusCode': 400,
       'message': 'Email Successfully Sent'
      }
Suraj Kulkarni
  • 121
  • 1
  • 4
  • 1
    Code-only answers are discouraged. Please click on [edit] and add some words summarising how your code addresses the question, or perhaps explain how your answer differs from the previous answer/answers. Thanks – Nick Dec 27 '18 at 07:36