Skip to main content
Solved

Returning multiple records from a PythonCreator - HOWTO


olly_egw

I am fairly new to FME and Python.

I have written the python script to extract emails from our outlook server. It is successfully pulling down each email from a mailbox and separating out the body, subject, attachments , etc. These I have placed into attribute elements without any issues ( code below ).

The problem I have is returning each email in the transformer as a separate row. I only get the details of the last email I am downloading. I would like each email to be returned as a dataset - eg the data inspector should show 7 rows for 7 emails.

Any assistance on how I do this thru the pythoncreator transformer would be greatly appreciated.

Many thanks

Olly

 

import fme

 

import fmeobjects

 

import sys

 

import email

 

import imaplib

 

import os

 

import base64

 

def processFeature(feature):

 

emails = FeatureProcessor()

 

emails.getEmails(feature)

class FeatureProcessor(object):

mail_server = FME_MacroValues['Pop3Host']

 

deletefromserver = FME_MacroValues['DeleteFromServer']

 

mail = None

def __init__(self):

username = FME_MacroValues['UserName']

 

password = FME_MacroValues['Password']

self.mail = imaplib.IMAP4_SSL( self.mail_server, 993 )

 

self.mail.login( username, password )

 

self.mail.select( 'Inbox' )

def getEmails(self, feature):

resp, data = self.mail.search(None, 'ALL' )

 

try:

 

if (resp != 'OK' ):

 

raise Exception('Error connecting to ' + self.mail_server + ' : ' + resp )

mail_ids = data[0]

 

id_list = mail_ids.split()

print('-'*20)

 

print(self.mail.welcome)

 

print('New Messages: %d ' % len( id_list ))

 

print('-'*20)

 

 

feature.setAttribute('NumberOfEmails', len( id_list ) )

#process each new email

 

for num in data[0].split():

 

typ, full_msg = self.mail.fetch(num, '(RFC822)' )

 

self.process_email(full_msg, num, feature)

except:

 

print('Error: {0}'.format(sys.exc_info()[0]))

def get_email_body( self, email_message):

 

if email_message.is_multipart():

 

for p in email_message.walk():

 

if p.get_content_type() == 'text/plain' and 'attachment' not in str( p.get( 'Content-Disposition' ) ):

 

return p.get_payload(decode=True)

 

else:

 

return email_message.get_payload(decode=True)

 

def get_email_attachments(self, email_message):

SaveAttachmentsDirectory = FME_MacroValues['SaveAttachmentsDirectory']

 

attachments = []

for part in email_message.walk():

 

if part.get_content_maintype() == 'multipart':

 

continue

 

if part.get('Content-Disposition') is None:

 

continue

fileName = part.get_filename()

 

attachments.append( fileName )

if bool(fileName):

 

filePath = os.path.join( SaveAttachmentsDirectory , fileName)

 

if not os.path.isfile(filePath) :

 

fp = open(filePath, 'wb')

 

fp.write(part.get_payload(decode=True))

 

fp.close()

#print( 'Attachments extracted: ', attachments )

 

if attachments == None :

 

return ""

 

else:

 

return attachments

def process_email(self, full_msg, num, feature):

 

 

raw_email = full_msg[0][1] # converts byte literal to string removing b''

 

raw_email_string = raw_email.decode('utf-8')

 

email_message = email.message_from_string(raw_email_string)

msg_subject = None

 

msg_from = None

 

msg_body = None

 

msg_attachments = []

#other email meta data

 

for response_part in full_msg:

 

if isinstance(response_part, tuple):

 

msg = email.message_from_string(response_part[1].decode('utf-8'))

 

msg_subject = msg['subject']

 

msg_from = msg['from']

print('Downloading message : ' + str(num) + ' titled: ' + msg_subject )

msg_body = self.get_email_body( email_message )

 

msg_attachments = self.get_email_attachments( email_message )

 

 

feature.setAttribute('from', msg_from)

 

feature.setAttribute('subject', msg_subject)

 

feature.setAttribute('attachments', msg_attachments )

 

 

feature.setAttribute('body', msg_body.decode('utf-8') )

return

 

def input(self,feature):

 

self.pyoutput(feature)

 

def close(self):

 

# mailbox cleanup and close and logout session

 

if self.deletefromserver == 'Yes':

 

self.mail.expunge()

self.mail.close()

 

self.mail.logout()

Best answer by meijer

You python code is a bit hard to read without indentation. I guess you can move some (or even all) logic from your __init__ to def input. In the __init are features not yet made. That happens in the def input.

 

 

What you want to do in basic, is to create features and output them (or copy) within a kind of loop.

 

Here I have a loop that output for every index a FME feature.

 

Per feature you can also set attributes.
View original
Did this help you find an answer to your question?

3 replies

meijer
Contributor
Forum|alt.badge.img+3
  • Contributor
  • Best Answer
  • March 11, 2020

You python code is a bit hard to read without indentation. I guess you can move some (or even all) logic from your __init__ to def input. In the __init are features not yet made. That happens in the def input.

 

 

What you want to do in basic, is to create features and output them (or copy) within a kind of loop.

 

Here I have a loop that output for every index a FME feature.

 

Per feature you can also set attributes.

olly_egw
  • Author
  • March 11, 2020

Many thanks for that. I rewrote the code using the FME class template and added the recommended code. It now works as expected.


olly_egw
  • Author
  • March 11, 2020
olly_egw wrote:

Many thanks for that. I rewrote the code using the FME class template and added the recommended code. It now works as expected.

Many thanks for that.


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings