Code Samples: Python
IMPORTANT! C# is our official client and the only code that 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
- 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.
- Neither PyCrypto nor Python natively support PKCS7, so included is some commonly used code for that function.
- 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.
- 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.