My Python script takes a list of lists and creates the text of an email body by joining the inner lists' elements with a "," and appends each of these with a newline like so:
for row in rows:
emailBody += ",".join(row) + "\n"
(I know that I can do something similar using the CSV module, but I'm aiming to do without it - at least for now.)
Then later it sends the email by using:
import smtplib
from email.mime.text import MIMEText
smtpServer = serverDNS
msg = MIMEText(emailBody, "plain")
msg['from'] = fromAddress
msg['to'] = ", ".join(recipients)
msg['subject'] = subject
smtp = smtplib.SMTP(smtpServer)
smtp.sendmail(msg['from'], recipients, msg.as_string())
smtp.quit()
This works fine, except that the newline on the first line gets ignored and the first two lines end up on one line. The newline on every other line is just fine.
If I manually add an extra newline to the last item of the first line, then the email has TWO newlines after the first line, so that there is a blank line between the first two lines.
What is going on here? How can I get this to behave as expected?
Note that the first line (the first list) consists of a bunch of hard-coded strings. So it's a very simple list. All the other lines are dynamically generated, but are all simple string values in the end (otherwise the 'join' would complain, right?).
If I simply print emailBody, it prints fine. It is only when converting it to an email that the first line's newline gets lost.
I've also tried using "\r\n" instead of just "\n". Same result.
This appears to be an OUTLOOK "Feature" (I'd call it a bug!), not a problem with my Python code. Unfortunately, I'm stuck with Outlook at work. But I found that if I send the email to both the work address and my private address, it shows up perfectly fine on my private email, but wrong in my work email!
Then I noticed that in Outlook, there is a line of small grey text near the top of the email that says "Extra line breaks in this message were removed." Clicking on this line restores the line breaks and the email is then displayed correctly!
Any idea why Outlook does this? Any idea why it does this on some lines and not others, and how I can code my Python to send emails that wont make Outlook "fix" them?
Outlook Fix:
Unfortunately, I can't do this for all the people that may receive these emails. However, I did find a preference in Outlook for "Remove extra line breaks in plain text messages" which was on, so I've turned it off, and this has resolved the problem in my Outlook client, at least.
I will have to communicate this to all other recipients of these emails if I cannot figure out how to format them so that Outlook doesn't try to "Fix" them.
Related
i have recently started building a bot in discord.py and got stuck in this situation here
#client.command()
async def replace(ctx, *, arg):
msg = f"{arg}" .format(ctx.message).replace('happe', '<:happe:869470107066302484>')
await ctx.send(msg)
this is a command which replaces the word "happe" with the emoji so this looks like :
Command : {prefix}replace i am very happe
Result : i am very "emoji for happe"
but i want to make it so we can replace multiple words with different emoji and not just a single one like
Command : {prefix}replace i am not happe, i am sad
Result : i am not "emoji for happe", i am "emoji for sad"
is there a way to edit multiple words in just one sentence like using a json file of making a list of emojis and its id?
also this command doesnt seems to work in cogs and says command is invalid
is there a way to edit multiple words in just one sentence like using a json file ot making a list of emojis and its id?
Yes, you can do just that. Make a list of word-emoji pairs and iterate over all of them to replace every word.
async def replace(ctx, *, arg):
l = [("happe", "<:happe:869470107066302484>"), ("sad", "..."), ...]
msg = arg # Making a copy here to avoid editing the original arg in case you want to use it at some point
for word, emoji in l:
msg = msg.replace(word, emoji)
await ctx.send(msg)
also this command doesnt seems to work in cogs and says command is invalid
In cogs the decorator is #commands.command(), not #client.command(). Don't forget the from discord.ext import commands import to get access to it.
Lastly, I'm a bit confused what f"{arg}" .format(ctx.message) is supposed to be doing? You can remove the .format and the f-string entirely. args is already a string so putting it in an f-string with nothing else has no effect, and .format(ctx.message) doesn't do anything either. The result of that entire thing is the same as just arg.
>>> arg = "this is the arg"
>>> f"{arg}".format("this has no effect")
'this is the arg'
I'm trying to write my own Jekyll plugin to construct an api query from a custom tag. I've gotten as far as creating the basic plugin and tag, but I've run into the limits of my programming skills so looking to you for help.
Here's my custom tag for reference:
{% card "Arbor Elf | M13" %}
Here's the progress on my plugin:
module Jekyll
class Scryfall < Liquid::Tag
def initialize(tag_name, text, tokens)
super
#text = text
end
def render(context)
# Store the name of the card, ie "Arbor Elf"
#card_name =
# Store the name of the set, ie "M13"
#card_set =
# Build the query
#query = "https://api.scryfall.com/cards/named?exact=#{#card_name}&set=#{#card_set}"
# Store a specific JSON property
#card_art =
# Finally we render out the result
"<img src='#{#card_art}' title='#{#card_name}' />"
end
end
end
Liquid::Template.register_tag('cards', Jekyll::Scryfall)
For reference, here's an example query using the above details (paste it into your browser to see the response you get back)
https://api.scryfall.com/cards/named?exact=arbor+elf&set=m13
My initial attempts after Googling around was to use regex to split the #text at the |, like so:
#card_name = "#{#text}".split(/| */)
This didn't quite work, instead it output this:
[“A”, “r”, “b”, “o”, “r”, “ “, “E”, “l”, “f”, “ “, “|”, “ “, “M”, “1”, “3”, “ “]
I'm also then not sure how to access and store specific properties within the JSON response. Ideally, I can do something like this:
#card_art = JSONRESPONSE.image_uri.large
I'm well aware I'm asking a lot here, but I'd love to try and get this working and learn from it.
Thanks for reading.
Actually, your split should work – you just need to give it the correct regex (and you can call that on #text directly). You also need to escape the pipe character in the regex, because pipes can have special meaning. You can use rubular.com to experiment with regexes.
parts = #text.split(/\|/)
# => => ["Arbor Elf ", " M13"]
Note that they also contain some extra whitespace, which you can remove with strip.
#card_name = parts.first.strip
#card_set = parts.last.strip
This might also be a good time to answer questions like: what happens if the user inserts multiple pipes? What if they insert none? Will your code give them a helpful error message for this?
You'll also need to escape these values in your URL. What if one of your users adds a card containing a & character? Your URL will break:
https://api.scryfall.com/cards/named?exact=Sword of Dungeons & Dragons&set=und
That looks like a URL with three parameters, exact, set and Dragons. You need to encode the user input to be included in a URL:
require 'cgi'
query = "https://api.scryfall.com/cards/named?exact=#{CGI.escape(#card_name)}&set=#{CGI.escape(#card_set)}"
# => "https://api.scryfall.com/cards/named?exact=Sword+of+Dungeons+%26+Dragons&set=und"
What comes after that is a little less clear, because you haven't written the code yet. Try making the call with the Net::HTTP module and then parsing the response with the JSON module. If you have trouble, come back here and ask a new question.
For educational purposes I am trying to scrape this page using lxml and requests in Python.
Specifically I just want to print the research areas of all the professors on the page.
This is what I have done till now
import requests
from lxml import html
response=requests.get('http://cse.iitkgp.ac.in/index.php?secret=d2RkOUgybWlNZzJwQXdLc28wNzh6UT09')
parsed_body=html.fromstring(response.content)
for row in parsed_body.xpath('//div[#id="maincontent"]//tr[position() mod 2 = 1]'):
for column in row.xpath('//td[#class="fcardcls"]/tr[2]/td/font/text()'):
print column.strip()
But it is not printing anything. I was struggling quite a bit with xpaths and was intially using the copy xpath feature in chrome. I followed what was done in the following SO questions/answers and cleaned up my code quite a bit and got rid of ' tbody ' in the xpaths. Still the code returns a blank.
1. Empty List Returned
2. Python-lxml-xpath problem
First of all, the main content with the desired data inside is loaded from a different endpoint via an XHR request - simulate that in your code.
Here is the complete working code printing names and a list of research areas per name:
import requests
from lxml import html
response = requests.get('http://cse.iitkgp.ac.in/faculty4.php?_=1450503917634')
parsed_body = html.fromstring(response.content)
for row in parsed_body.xpath('.//td[#class="fcardcls"]'):
name = row.findtext(".//a[#href]/b")
name = ' '.join(name.split()) # getting rid of multiple spaces
research_areas = row.xpath('.//*[. = "Research Areas: "]/following-sibling::text()')[0].split(", ")
print(name, research_areas)
The idea here is use the fact that all "professor blocks" are located in td elements with class="fcardcls". For every block, get the name from the bold link text and research areas from the following string after Research Areas: bold text.
I am using django-registration and for some reason, when it sends the activation email, it inserts an equals sign in the third to last character as such: http://example.com/accounts/activate/a65b4aca5156211bc522e29f3e872290544d14=
e4/
This means the URL dispatcher does not catch the URL (the regex is ^activate/(?P<activation_key>\w+)/$. The url is incorrect anyway, as it should be without the equals sign.
Anybody know why this is happening?
Your email client isn't reading the quoted-printable-encoded message properly. A = at the end of a line means that the line should be concatenated with the following line seamlessly.
Nearing what I would like to think is completion on a tool I've been working on. What I've got going on is some code that does essentially this:
open several files and urls which consist of known malware/phishing related websites/domains and create a list for each, Parse the html of a url passed when the method is called, pulling out all the a href links and placing them in a separate list,
for every link that was placed in the new list, create a regex for every item thats in the malware and phishing lists, and then compare against to determine if any of the links parsed from the URL passed when the method was called are malicious.
The problem I've ran into is in iterating over the items of all 3 lists, obviously I'm doing it wrong since its throwing this error at me:
File "./test.py", line 95, in <module>
main()
File "./test.py", line 92, in main
crawler.crawl(url)
File "./test.py", line 41, in crawl
self.reg1 = re.compile(link1)
File "/usr/lib/python2.6/re.py", line 190, in compile
return _compile(pattern, flags)
File "/usr/lib/python2.6/re.py", line 245, in _compile
raise error, v # invalid expression
sre_constants.error: multiple repeat
The following is the segment of code I'm having problems with, with the malware related list create omitted as that part is working fine for me:
def crawl(self, url):
try:
doc = parse("http://" + url).getroot()
doc.make_links_absolute("http://" + url, resolve_base_href=True)
for tag in doc.xpath("//a[#href]"):
old = tag.get('href')
fixed = urllib.unquote(old)
self.links.append(fixed)
except urllib.error.URLERROR as err:
print(err)
for tgt in self.links:
for link in self.mal_list:
self.reg = re.compile(link)
for link1 in self.phish_list:
self.reg1 = re.compile(link1)
found = self.reg.search(tgt)
if found:
print(found.group())
else:
print("No matches found...")
Can anyone spot what I've done wrong with the for loops and list iteration that would be causing that regex error? How might I fix it? And probably most importantly is the way I'm going about doing this 'pythonic' or even efficient? Considering what I'm trying to do here, is there a better way of doing it?
It seems like your problem is that some of the URLs contain special regex characters, such as ? and +; for instance, the string ++ is really quite likely. The other problem is that you keep overwriting the regex you're using to test. If you just need to check if one string is contained in another, there's no need for a regex; just use
for tgt in self.links:
for link in (self.mal_list + self.phish_list):
if link in tgt: print link
And if you're just comparing for equality, you can use == instead of in.