Smartsheet Send Email Failed by API - python

I'm trying to follow the API document and send an email by using my sheet.
Here is the code:
email = smartsheet.models.MultiRowEmail()
email.send_to = smartsheet.models.Recipient({
'email': 'testtest#gmail.com'
})
email.row_ids=[rowId]
email.column_ids = [columnID]
# Send rows via email
response = smartsheet_client.Sheets.send_rows(
sheet_id, # sheet_id
email)
It keeps giving me error message below,
{"response": {"statusCode": 400, "reason": "Bad Request", "content": {"errorCode": 1012, "message": "Required object attribute(s) are missing from your request: multipleRowsEmail.rowIds[], multipleRowsEmail.includeAttachments, multipleRowsEmail.includeDiscussions.", "refId": "lvre2gkxtm8m"}}}
Please advise, Thanks

Part of the problem is that you need to also specify the include_attachments property and the include_discussions property on the email object. These properties are required. (As a sidenote, I notice that the Python code snippet for Send Rows via Email in the API docs incorrectly omits these two properties...hopefully someone from Smartsheet sees this thread and can fix that issue in the docs.)
Not sure why the error message indicates that row IDs are missing from the request, as it looks like you're populating Row IDs. I'd suggest that you investigate to make sure that your [rowId] property (that you're using to set the value of email.row_ids in the request) actually is a populated array of Row IDs.
The following code example successfully sends an email that contains the specified 4 rows and 2 columns of data:
# specify IDs
sheet_id = 3932034054809476
row_ids = [4324392993613700, 5225480965908356, 657918269646724, 721881338537860]
column_ids = [6101753539127172, 4055216160040836]
# build email object
email = smartsheet.models.MultiRowEmail()
email.send_to = smartsheet.models.Recipient({
'email': 'testtest#gmail.com'
})
email.row_ids = row_ids
email.column_ids = column_ids
email.include_attachments = False
email.include_discussions = False
# send rows via email
response = smartsheet_client.Sheets.send_rows(
sheet_id,
email)

Related

requests.post only accepts "text" dictionary values

I'm attempting to make post requests to slack from a requests.post() call. Here is an example of the code that I've made to do this:
fields = {
'sender': message['From'],
'subject': message['Subject'],
}
url = 'https://hooks.slack.com/services/XXXXXX'
print(fields)
return requests.post(url, json=fields)
The issue seems to be that the requests.post(url, json=fields) command only seems to respond to the fields command if I change the key value(s) to "text". I have no idea what is not allowing the requests.post command to use other key values (such as sender or subject) that I have defined here.
I have been able to fix this by doing a terrible workaround of calling two separate requests.post commands and setting sender/subject as their own variables with json formatted dictionaries:
sender = {'text': message['From']}
subject = {'text': message['Subject']}
Just a side-note I'm gathering these message handlers from aiosmtpd.handlers which allows me to parse smtp messages that come in.

Python and mailchimp integration

So i have been stuck on this for a week or so and could really do this some advice.
I have a basic website which allows people to sign up to an automated newsletter that i want to send out. After adding their email on the site their address is automatically added to an audience.
I have a small python script running that then web scrapes a site and then if that returns a certain criteria it will send an automated email out via mailchimp to all the contacts in the mailchimp audience.
What i am having issue with is actually creating and sending out the email via mail chimp.
I have been through https://mailchimp.com/developer/api/marketing/campaigns/add-campaign/ a few times and can't seem to get it working. I am able to create a new campaign succesfully as well as the audience and subject line. I am unable to workout how to actually send the email with the content i want inside it however. It just saves itself as a draft and thats it.
When i try to preview the email there is nothing in it and when i click edit next to the campaign everything is ticked except for the 'content.
I have excluded th web scraping part of my program but below is the test i am running to create and sent out via the mailchimp api
import mailchimp_marketing as MailchimpMarketing
from mailchimp_marketing.api_client import ApiClientError
from mailchimp3 import MailChimp
data = {
"recipients" :
{
"list_id": 'XXXXXXXX'
},
"settings":
{
"subject_line": 'Subject of email',
"from_name": 'from_name',
"reply_to": 'reply_email',
},
"type": "regular"
}
try:
client = MailchimpMarketing.Client()
#print(client)
client.set_config({
"api_key": "XXXXXXXXXXXXXXXX",
"server": "XXXXXXX"
})
#client = MailChimp(mc_api='XXXXXXXXXXXX', mc_user="XXXXXXXXX")
client.campaigns.create(data)
response = client.campaigns.get('campaign_id')
#client.campaigns.send()
print(response)
except ApiClientError as error:
print("Error: {}".format(error.text))
This succesfully creates the campaign except without the content that i want to add and simply saves the email as a draft without send. So i guess my question is how to i edit the email content and then how do i actually initiate the send.
Thanks for any help
I also didn't find a minimal example on the web. Plus the examples in the mailchimp api documentation are severely lacking for python (only curl seems correct). Here's a minimal example:
from mailchimp_marketing import Client, api_client
# find this out at https://mailchimp.com/en/help/about-api-keys/
API_KEY = '…'
# log into your Mailchimp account and look at the URL in your browser.
# You’ll see something like https://us19.admin.mailchimp.com/
# the us19 part is the server prefix.
SERVER_PREFIX = 'us19'
try:
client = Client()
client.set_config({
"api_key": API_KEY,
"server": SERVER_PREFIX
})
# find out list id: https://mailchimp.com/en/help/find-audience-id/
campaign_data = dict(
type='regular',
recipients=dict(list_id='…'),
settings=dict(
subject_line='lorem ipsum',
from_name='John Doe',
reply_to='john#doe.com',
)
)
campaign = client.campaigns.create(campaign_data)
print(campaign)
campaign_id = campaign['id']
content_data = dict(
plain_text='lorem ipsum',
html='<p><strong>lorem</strong><br />ipsum</p>'
)
response = client.campaigns.set_content(campaign_id, content_data)
print(response)
response = client.campaigns.send(campaign_id)
print(response)
except api_client.ApiClientError as e:
print("Error: {}".format(error.text))

Creating POST request in python, need to send data as multipart/form-data?

I'm in the process of writing a very simple Python application for a friend that will query a service and get some data in return. I can manage the GET requests easily enough, but I'm having trouble with the POST requests. Just to get my feet wet, I've only slightly modified their example JSON data, but when I send it, I get an error. Here's the code (with identifying information changed):
import urllib.request
import json
def WebServiceClass(Object):
def __init__(self, user, password, host):
self.user = user
self.password = password
self.host = host
self.url = "https://{}/urldata/".format(self.host)
mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
mgr.add_password(None, "https://{}".format(self.host), self.user, self.password)
self.opener = urllib.request.build_opener(urllib.request.HTTPDigestAuthHandler(mgr))
username = "myusername"
password = "mypassword"
service_host = "thisisthehostinfo"
web_service_object = WebServiceClass(username, password, service_host)
user_query = {"searchFields":
{
"First Name": "firstname",
"Last Name": "lastname"
},
"returnFields":["Entity ID","First Name","Last Name"]
}
user_query = json.dumps(user_query)
user_query = user_query.encode("ascii")
the_url = web_service_object.url + "modules/Users/search"
try:
user_data = web_service_object.opener.open(the_url, user_query)
user_data.read()
except urllib.error.HTTPError as e:
print(e.code)
print(e.read())
I got the class data from their API documentation.
As I said, I can do GET requests fine, but this POST request gives me a 500 error with the following text:
Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported
In researching this error, my assumption has become that the above error means I need to submit the data as multipart/form-data. Whether or not that assumption is correct is something I would like to test, but stock Python doesn't appear to have any easy way to create multipart/form-data - there are modules out there, but all of them appear to take a file and convert it to multipart/form-data, whereas I just want to convert this simple JSON data to test.
This leads me to two questions: does it seem as though I'm correct in my assumption that I need multipart/form-data to get this to work correctly? And if so, do I need to put my JSON data into a text file and use one of those modules out there to turn it into multipart, or is there some way to do it without creating a file?
Maybe you want to try the requests lib, You can pass a files param, then requests will send a multipart/form-data POST instead of an application/x-www-form-urlencoded POST. You are not limited to using actual files in that dictionary, however:
import requests
response = requests.post('http://httpbin.org/post', files=dict(foo='bar'))
print response.status_code
If you want to know more about the requests lib, and specially in sending multipart forms take a look at this:
http://docs.python-requests.org/en/master/
and
http://docs.python-requests.org/en/master/user/advanced/?highlight=Multipart-Encoded%20Files

Reading page's messages with Python Facebook SDK

Basically i need to get all messages of a page using facebook SDK in python.
Following some tutorial i arrived to this point:
import facebook
def main():
cfg = {
"page_id" : "MY PAGE ID",
"access_token" : "LONG LIVE ACCESS TOKEN"
}
api = get_api(cfg)
msg = "Hre"
status = api.put_wall_post(msg) #used to post to wall message Hre
x = api.get_object('/'+str(MY PAGE ID)+"/conversations/") #Give actual conversations
def get_api(cfg):
graph = facebook.GraphAPI(cfg['access_token'])
resp = graph.get_object('me/accounts')
page_access_token = None
for page in resp['data']:
if page['id'] == cfg['page_id']:
page_access_token = page['access_token']
graph = facebook.GraphAPI(page_access_token)
return graph
if __name__ == "__main__":
main()
The first problem is that api.get_object('/'+str(MY PAGE ID)+"/conversations/")returns a dictionary containing many informations, but what i would like to see is the messages they sent to me, while for now it print the user id that sent to me a message.
The output look like the following:
{u'paging': {u'next': u'https://graph.facebook.com/v2.4/571499452991432/conversations?access_token=Token&limit=25&until=1441825848&__paging_token=enc_AdCqaKAP3e1NU9MGSsvSdzDPIIDtB2ZCe2hCYfk7ft5ZAjRhsuVEL7eFYOOCdQ8okvuhZA5iQWaYZBBbrZCRNW8uzWmgnKGl69KKt4catxZAvQYCus7gZDZD', u'previous': u'https://graph.facebook.com/v2.4/571499452991432/conversations?access_token=token&limit=25&since=1441825848&__paging_token=enc_AdCqaKAP3e1NU9MGSsvSdzDPIIDtB2ZCe2hCYfk7ft5ZAjRhsuVEL7eFYOOCdQ8okvuhZA5iQWaYZBBbrZCRNW8uzWmgnKGl69KKt4catxZAvQYCus7gZDZD&__previous=1'}, u'data': [{u'link': u'/communityticino/manager/messages/?mercurythreadid=user%3A1055476438&threadid=mid.1441825847634%3Af2e0247f54f5c4d222&folder=inbox', u'id': u't_mid.1441825847634:f2e0247f54f5c4d222', u'updated_time': u'2015-09-09T19:10:48+0000'}]}
which is basically paging and data.
Given this is there a way to read the conversation?
In order to get the messages content you need first to request the single messages in the conversation, accessible with the 'id' field in the dictionary you copied, result of
x = api.get_object('/'+str(MY PAGE ID)+"/conversations/") #Give actual conversations
you can request the messages in the conversation by calling
msg = api.get_object('/'+<message id>)
Here it gets tricky, because following the graph api documentation you should receive back a dictionary with ALL the possible fields, including the 'message' (content) field. The function however returns only the fields 'created_time' and 'id'.
Thanks to this other question Request fields in Python Facebook SDK I found that you can request for those fields by adding a dict with such fields specified in the arguments of the graph.get_object() function. As far as I know this is undocumented in the facebook sdk reference for python.
The correct code is
args = {'fields' : 'message'}
msg = api.get_object('/'+<message id>, **args)
Similar question: Read facebook messages using python sdk

Printing out post data

i have a small script that reads and parse emails and check them against a database to assist me with resetting passwords,
unfortunately i have a bug and i can't seems to find it, currently i'm trying to visually check if there's a difference in the details (hopefully finding a pattern).
this is the relevant parts of the code:
def send_device_match_reset(username, email):
return requests.post(
'https://api.parse.com/1/requestPasswordReset',
headers=parse_headers,
data=json.dumps({
'username': username.upper(),
'email': email.encode('ascii', 'xmlcharrefreplace'),
'code': '*********'
})
)
and
if user.has_key('emailAddress'):
if user.get('emailAddress') == email:
reset_response = send_device_match_reset(username.encode('ascii', 'xmlcharrefreplace'), email.encode('ascii', 'xmlcharrefreplace'))
print "response code", reset_response.status_code
if reset_response.status_code != 200:
log.error('send_device_match_reset failed with %s:%s'%(username,email))
log.error('logging msg: %s'%(reset_response.text))
log.error('email: %s'%(email.encode('ascii', 'xmlcharrefreplace')))
log.error('username: %s'%(username.encode('ascii', 'xmlcharrefreplace')))
return
log.info('Recovered using verified email')
return message_processed(message, 'RecoveredByEmail', user=user)
now i'm trying to figure out how to print the actual headers from the #1st section "data"
inside my "log.error" debug lines.
i've been trying a direct approach by doing:
log.error(requests.post);
or
log.error(requests.post(data));
but it doesn't work - and i don't know python good enough to understand why.
log.error(requests.post); prints the function pointer
log.error(requests.post(data)); prints the result of the function, since data ist defined globally -> error
Try log.error(parse_headers) since this variable seems to be defined globally, it should work for you.
However, I normally stringify my variables like '{0}'.format(var) to enure, that I am working with a string afterwards.
EDITED:
def send_device_match_reset(username, email):
data = json.dumps({
'username': username.upper(),
'email': email.encode('ascii', 'xmlcharrefreplace'),
'code': '*********'
})
log.error('sending: data = {0}'.format(data))
return requests.post(
'https://api.parse.com/1/requestPasswordReset',
headers = parse_headers,
data = data
)

Categories

Resources