Code Samples: Python

Please note that C# is our Official client, and that is what we support.  This Python code has been provided by another customer and we encourage you to let us know if you find any problems so that we can update accordingly.

Sendfax Method

#CORE PYTHON IMPORTS
import logging, sys, time, urllib, base64, urllib2
import simplejson as json
from xml.dom.minidom import parseString
#SRC IMPORTS
import webservice
from pkcs7 import PKCS7Encoder
#DEPENDENCY IMPORTS -- PyCrypto (https://www.dlitz.net/software/pycrypto/ OR <a href="http://pypi.python.org/pypi/pycrypto/2.5">http://pypi.python.org/pypi/pycrypto/2.5</a>)
from Crypto.Cipher import AES
USERNAME = "" Enter a valid Username
APIKEY = "" Enter a valid ApiKey
ENCRYPTIONKEY = "" Enter a valid EncryptionKey
VECTOR = "" Enter a valid Vector
URL = "https://api.sfaxme.com"
DOWNLOAD_DIR = "C:\\Temp\\faxes\\"
def getToken():#Generating token
    print ("sfaxWS.py -> getToken")
    try:
        timestr = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
        raw = "Username="+USERNAME+"&ApiKey="+APIKEY+"&GenDT="+timestr+"&"
        mode = AES.MODE_CBC
        encoder = PKCS7Encoder()
        encryptor = AES.new(ENCRYPTIONKEY, mode, VECTOR.encode("ascii"))
        pad_text = encoder.encode(raw)
        cipher = encryptor.encrypt(pad_text)
        enc_cipher = base64.b64encode(cipher)
        return urllib.quote_plus(enc_cipher)
    except:
       print ("Error getting token " + str(sys.exc_info()[0]) + " " + str(sys.exc_info()[1]))
    return 
"""
    RETURN THE SENDFAXQUEUEID  OF THE OUTGOING FAX, OTHERWISE RETURN NONE IF FAILED TO SEND
"""
def sendFax(fax):
    print ("sfaxWS.py -> sendFax")
    tid = None
    XwsSuccess = "true"
    try:  
            path = "/api/sendfax?token="+getToken()+"&ApiKey="+APIKEY+"&RecipientName=Gene&RecipientFax="+ str(fax)+"&OptionalParams=&"
            response = webservice.post(URL2, path)
            if XwsSuccess == "true":
                print ("Fax successfully submitted to sfax for delivery to " + str(fax))
                result = json.load(urllib2.urlopen(response))
                tid = result['SendFaxQueueId']
                print tid
            else:
                err = "Error submitting fax for send to " + str(fax)
                err += " ResultCode=" + str(response.getheader("XwsFaxResultCode")) + " ResultInfo=" + str(response.getheader("XwsResultInfo"))
                err += " ErrorCode=" + str(response.getheader("XwsFaxErrorCode")) + " ErrorInfo=" + str(response.getheader("XwsErrorInfo"))
                print (err)
    except:
        print ("Error transmitting data to sfax " + str(sys.exc_info()[0]) + " " + str(sys.exc_info()[1]))
    return tid

SendfaxStatus Method

"""
RETURN THE STATUS OF AN OUTGOING FAX 
"""    
def getStatus(tid):
    XwsSuccess = "true"
    print ("sfaxWS.py -> getStatus")
    print ("Checking status on " + tid)
    ret = (True)
    path = "/api/sendfaxstatus?token="+getToken()+"&ApiKey="+APIKEY+"&SendFaxQueueId="+ str(tid)
    response = webservice.get(URL, path)
    if XwsSuccess == "true":  
        #sFax is no longer trying to send this fax. Find out what the result was...
        SendResponse = urllib2.urlopen(response).read()
        result = json.load(urllib2.urlopen(response))
        status = result['message']
        print status
    else:
        err = "Error checking fax status for tid " + tid
        err += " ResultCode=" + response.getheader("XwsFaxResultCode") + " ResultInfo=" + response.getheader("XwsResultInfo")
        err += " ErrorCode=" + response.getheader("XwsFaxErrorCode") + " ErrorInfo=" + response.getheader("XwsErrorInfo")
        """log.warn(err)"""
        print (err)
    return ret
# USAGE
#*********************************************************
tid = sendFax("C:\\Temp\\test2.pdf", "15123668506")
getStatus(tid)
complete, success, faxAttempt = getStatus(tid)
print (complete,success,int(faxAttempt))
while True:
    getStatus(tid)
    complete, success, faxAttempt = getStatus(tid)
    print (complete,success,int(faxAttempt))
    tids = inboundFaxRetrieveSet()
    for t in tids:
        inboundFaxDownload(t)
    time.sleep(60)
print "************************* DONE *************************"

webservice.py

import httplib
from poster.encode import multipart_encode
from poster.streaminghttp import register_openers
import urllib2
def post(URL, path, file_to_upload ):
    # Register the streaming http handlers with urllib2
    register_openers()
# Start the multipart/form-data encoding of the file "DSC0001.jpg"
# "image1" is the name of the parameter, which is normally set
# via the "name" parameter of the HTML <input> tag.
# headers contains the necessary Content-Type and Content-Length
# datagen is a generator object that yields the encoded parameters
    datagen, headers = multipart_encode({"file.pdf": open("C:\\temp\\test2.pdf", "rb")})
# Create the Request object
    response = urllib2.Request(URL + path, datagen, headers)
# Actually do the request, and get the response
    print urllib2.urlopen(response).read()
    #print urllib2.urlopen(response).info().items()
    return response
def get(URL, path):
    register_openers()  
    response = urllib2.Request(URL + path)
    print urllib2.urlopen(response).read()
    return response

pkcs7.py

import binascii
import StringIO
class PKCS7Encoder(object):
    '''
    RFC 2315: PKCS#7 page 21
    Some content-encryption algorithms assume the
    input length is a multiple of k octets, where k > 1, and
    let the application define a method for handling inputs
    whose lengths are not a multiple of k octets. For such
    algorithms, the method shall be to pad the input at the
    trailing end with k - (l mod k) octets all having value k -
    (l mod k), where l is the length of the input. In other
    words, the input is padded at the trailing end with one of
    the following strings:
             01 -- if l mod k = k-1
            02 02 -- if l mod k = k-2
                        .
                        .
                        .
          k k ... k k -- if l mod k = 0
    The padding can be removed unambiguously since all input is
    padded and no padding string is a suffix of another. This
    padding method is well-defined if and only if k < 256;
    methods for larger k are an open issue for further study.
    '''
    def __init__(self, k=16):
        self.k = k
    ## @param text The padded text for which the padding is to be removed.
    # @exception ValueError Raised when the input padding is missing or corrupt.
    def decode(self, text):
        '''
        Remove the PKCS#7 padding from a text string
        '''
        nl = len(text)
        val = int(binascii.hexlify(text[-1]), 16)
        if val > self.k:
            raise ValueError('Input is not padded or padding is corrupt')
        l = nl - val
        return text[:l]
    ## @param text The text to encode.
    def encode(self, text):
        '''
        Pad an input string according to PKCS#7
        '''
        l = len(text)
        output = StringIO.StringIO()
        val = self.k - (l % self.k)
        for _ in xrange(val):
            output.write('%02x' % val)
        return text + binascii.unhexlify(output.getvalue())

ReceiveInboundFax Sample

""
CHECK TO SEE IF THERE ARE INBOUND FAXES TO DOWNLOAD
"""
def inboundFaxRetrieveSet():
    XwsSuccess = "true"
    faxid = None
    """log = logging.getLogger("sfaxWS.py -> inboundFaxRetrieveSet")"""
    print ("sfaxWS.py -> inboundFaxRetrieveSet")
    """log.info(".")"""
    #print (".")
    tid = []
    fids = []
    path = "/api/receiveinboundfax?token="+getToken()+"&ApiKey="+APIKEY
    response = webservice.get(URL2, path,)
    GetResponse = urllib2.urlopen(response).read()
    print GetResponse
    result = json.loads(GetResponse)
    print result
    faxid = result
    for x in faxid['InboundFaxItems']:
        print "FaxId:", x['FaxId']
    fids = x['FaxId']
    return tid

DownloadInboundFaxasPdf Sample

DOWNLOAD AN INBOUND FAX as PDF
"""
def inboundFaxDownload(FaxId):#Enter a valid FaxId
    XwsSuccess = "true"
    print ("sfaxWS.py -> inboundFaxDownload")
    print ("downloading " + FaxId)
    path = "/api/downloadinboundfaxaspdf?token="+getToken()+"&ApiKey="+APIKEY+"&FaxId="+FaxId
    response = webservice.get(URL2 , path)
    if XwsSuccess == "true":
        GetResponse = urllib2.urlopen(response).read()
        filename = FaxId
        data = GetResponse
        with open(DOWNLOAD_DIR+filename+".pdf", "wb") as f:
            f.write(data)

DownloadInboundFaxAsTif – Sample

DOWNLOAD AN INBOUND FAX as TIF
"""
def inboundFaxDownload(FaxId):#Enter a valid FaxId
    XwsSuccess = "true"
    print ("sfaxWS.py -> inboundFaxDownload")
    print ("downloading " + '2121018144829980894')
    path = "/api/downloadinboundfaxastif?token="+getToken()+"&ApiKey="+APIKEY+"&FaxId="+FaxId
    response = webservice.get(URL2 , path)
    if XwsSuccess == "true":
        GetResponse = urllib2.urlopen(response).read()
        filename = FaxId
        data = GetResponse
        with open(DOWNLOAD_DIR+filename+".tif", "wb") as f:
            f.write(data)

Notes

  1. There are 3 external dependencies on PyCrypto, simplejson and poster. Python core does not natively support AES. PyCrypto, simplejson and poster are all python endorsed third party lib.
  2. Neither PyCrypto nor Python natively support PKCS7, so included is some commonly used code for that function. 
  3. Not all available functions are represented here at the moment only the sending of a fax and checking the initial status of the fax are represented here. 
  4. You may need to initialize python logging to use these files out of the box with log.xxx, or you can use print statements as represented.