Server Tools, Extract Data Model, Email link instead of ZIP

1017
4
04-09-2013 03:06 PM
KristenWobbe
Occasional Contributor II
I'm struggling with this one, and hope someone out there can help!

I have added a customization to the out of the box, ArcToolbox/Server Tool/Extract Data task, because if the data to download is over 1 Mb, I want the program to email a link to the user pointing to a folder location on the web server.  This way the user can retrieve the ZIP containing the data via the web link, rather than emailing the ZIP itself.

Problem:
The model runs FINE in ArcMAP and emails the link correctly and puts the zip in the web folder:
http://my server.agency.net/gpt_download/fef8a5cf-3306-4b0e-99d2-56191bcdd124.zip

NOT FINE (Send Email With Zip File Attachment script):
When you use the Web GUI (and the geoprocessing service) it emails the link with the backslash directly before the UUID going the wrong direction.
http://myserver/gpt_download\7ae66941-153a-468d-92c1-a867f5f15dc9.zip
With the result being it can't put the zip in the folder with the backslash going the wrong direction.

 

import arcgisscripting, smtplib, os, sys, traceback
import shutil
import uuid

from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders

gp = arcgisscripting.create(9.3)
# CONFIGURE EMAIL MESSAGE AND EMAIL SERVER

# REMOVE BEFORE RELEASE
_email_server = "smtp.blm.gov"

_email_send_from = "BLM Geoportal"
_email_subject = "The ZIP file containing your area of interest"
_email_body_zip_file_attached = "Attached is a ZIP file containing the data in the area of interest you specified."
_email_body_zip_file_oversize = "The resulting ZIP file is too large (%sMB).  Must be less than 5MB.  Please digitize a smaller Area of Interest."

_email_body_link_attached = "Click the link below to open the ZIP file containing the area of interest you specified."

#**********************************************************************
# Description:
#   Emails a file. File is assumed to be a zip file. Routine either attaches
#   the zip file to the email or sends the URL to the zip file.
#
# Parameters:
#   1 - File to send.
#   2 - Email address to send file.
#   3 - Name of outgoing email server.
#   4 - Output boolean success flag.
#**********************************************************************

def send_mail(send_from, send_to, subject, text, f, server, smtpUser="", smtpPwd="", sendZip="" ):
    try:
        msg = MIMEMultipart()
        msg['From'] = send_from
        msg['To'] = COMMASPACE.join(send_to)
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = subject

        if not sendZip:         # send URL to zip file
            text = text + "\n\n" + f
            msg.attach ( MIMEText(text) )
        else:
            msg.attach( MIMEText(text) )
            part = MIMEBase('application', "zip")   # Change if different file type sent.
            part.set_payload( open(f,"rb").read() )
            Encoders.encode_base64(part)
            part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
            msg.attach(part)
            
        smtp = smtplib.SMTP(server)
        
        # If your server requires user/password
        if smtpUser != "" and smtpPwd != "":
            smtp.login(smtpUser, smtpPwd)
        
        smtp.sendmail(send_from, send_to, msg.as_string())
        smtp.close()
    except:
        tb = sys.exc_info()[2]
        tbinfo = traceback.format_tb(tb)[0]
        pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n    " + \
                str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"
        raise Exception("SendEmailError:" + pymsg)

   
if __name__ == '__main__':

    sendto = gp.GetParameterAsText(0).split(";")
    fromaddr = gp.GetParameterAsText(1)
    subject = gp.GetParameterAsText(2)
    text = gp.GetParameterAsText(3)
    zipfile = gp.GetParameterAsText(4).replace("\\",os.sep)
    maxsize = int(gp.GetParameterAsText(5)) * 1000000
    smtpMailServer = gp.GetParameterAsText(6)
    smtpUser = gp.GetParameterAsText(7)
    smtpPwd = gp.GetParameterAsText(8)
    sendZip = gp.GetParameterAsText(9)
    
    # If sendZip is true, the zip file will be attached to the email.
    # If false, the URL to the zip will be in the body of the email.
    #
    sendZip = False
    subject = _email_subject
    
    try:
        if sendZip:
            # Attach zip
            #
            text = _email_body_zip_file_attached
            #Don't email large zip files.
            #    
            zipsize = os.path.getsize(zipfile)
            #Message"Zip file size = "
            gp.AddMessage(gp.GetIDMessage(86156) + str(zipsize))
            if  zipsize <= maxsize:
                send_mail(fromaddr, sendto, subject, text, zipfile, smtpMailServer, smtpUser, smtpPwd, sendZip)
                #Message "Sent zipfile to %s from %s"
                gp.AddIDMessage("INFORMATIVE", 86154, sendto, fromaddr)
                gp.SetParameterAsText(9, "True")
            else:
                #Message "The resulting zip file is too large (%sMB).  Must be less than %MB.  Please
                # digitize a smaller Area of Interest."
                gp.AddIDMessage("ERROR", 86155, str(round(zipsize / 1000000.0, 2)),
                            str(round(maxsize / 1000000.0, 2)))
                gp.SetParameterAsText(9, "False")
                raise Exception

        else:
            # Send URL instead of .zip file.  The jobs and virtual directory can be found
            #  in service's properties dialog box.  UNIX note: this code converts pathnames
            #  to lower case to  do the string replace.
            #
            text = "Click the link below to open zip file containing the area of interest you specified."
            #--- Start custom change to Send URL ---#
            # Purpose: Copy zipfile to URL virtual directory
            # And give the zipfile a unique filename
            # Requires import shutil and import uuid
            #TP downloadDir = r"C:\\arcgisserverdata\gpt_download"
            downloadDir = r"\\myserver\arcgisserverdata\gpt_download"
            virtualDir = "http://myserver.agency.net/gpt_download"
            # First generate a filename with a random unique identifier using uuid.uuid4()
            zipDownload = os.path.join(downloadDir, str(uuid.uuid4()) + ".zip")
            # Next copy the Source zipfile to the new Destination zipDownload
            shutil.copy2(zipfile, zipDownload)
            # Finally replace the local file system path with the web-accessible directory URL path
            url = zipDownload.replace(downloadDir, virtualDir)
            # Replace backslashes with URL forward slash convention
            #url = url.replace("\\", "/")
            newurl = url.replace("\\","/")
            
            #send_mail(_email_send_from, [sendto], subject, text, newurl, _email_server, sendZip)    
            send_mail(fromaddr, sendto, subject, text, newurl, smtpMailServer, smtpUser, smtpPwd, sendZip)
    except:
        # Return any python specific errors as well as any errors from the geoprocessor
        tb = sys.exc_info()[2]
        tbinfo = traceback.format_tb(tb)[0]
        pymsg = "PYTHON ERRORS:\nTraceback Info:\n" + tbinfo + "\nError Info:\n    " + \
                str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"
        gp.AddError(pymsg)
        #Message "Unable to send email"
  #gp.AddIDMessage("ERROR", 86157)
        gp.AddError("ERROR, Unable to send email")
        #gp.AddError(gp.GetIDMessage(86157))

Tags (2)
0 Kudos
4 Replies
AlexeyTereshenkov
Regular Contributor III
I know this is not the solution, but would you consider casting the result URL to a string and replacing the \ with the / in the string as a quick workaround?
0 Kudos
KristenWobbe
Occasional Contributor II
Thanks, yes this work-around did seem to help as more experienced python programmers (than myself) thought the "join" might be problematic.  Also following up with ESRI Help was useful too.

Accessing server directories through a virtual path, or URL
"ArcGIS 10.1 for Server allows you to access items from your server directories using virtual paths, or URLs."
0 Kudos
Thijsde_Boer
New Contributor
The workaround with casting the result URL to a string in not clear to me.
Could you write the code how and the place in the script where to do that please ?
0 Kudos
Thijsde_Boer
New Contributor
With the help of several people, we made the following working code:

            #TP downloadDir = r"C:\arcgisserverdata\gpt_download"
            downloadDir = r"E:\arcgisserverdata\gpt_download"
            virtualDir = "http://myserver.faculty.university.state/arcgisoutput/scratch"
            # First generate a filename with a random unique identifier using uuid.uuid4()
            zipDownload = os.path.join(downloadDir, str(uuid.uuid4()) + ".zip")
            # Next copy the Source zipfile to the new Destination zipDownload
            shutil.copy2(zipfile, zipDownload)
            # Finally replace the local file system path with the web-accessible directory URL path
            url = zipDownload.replace(downloadDir, virtualDir)
            url = str(url).replace("\\","/")
            # Replace backslashes with URL forward slash convention
            #url = url.replace("\\", "/")
            newurl = url.replace("\\","/")

Thank you all who contributed !
0 Kudos