ハマったこと
この3日間悩みまくりました。
結論から言うと、メールソフトはメールサーバーで扱え・・・
コード
最初はPOSTでFASTAPIに送ろうとしてたけど、エラー404 not foundが消えず。
もう半ばあきらめた時に、とっさに閃いたのは、結局は前回と同じで
pythonのメールサーバーに送ればいいんじゃない?
方針変えてからコードが動くまでは、あっと言う間でした。
cs.cs
using System;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.Outlook;
using System.Net.Mail;
using Attachment = Microsoft.Office.Interop.Outlook.Attachment;
namespace SampleRibbonOutlookAddIn
{
[ComVisible(true)]
public class Ribbon : IRibbonExtensibility
{
string REDMINE = "redmine@admin.com";
public void onMyButton_Click(IRibbonControl control)
{
Microsoft.Office.Interop.Outlook.MailItem mailItem = GetSelectedMailItem();
// Prompt the user to confirm sending to Redmine
DialogResult result = MessageBox.Show(
mailItem.Subject, "Send to Redmine?",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question
);
if (result == DialogResult.Yes) {
if (mailItem != null) {
// Call the Redmine API function with the email subject as the issue title
Post_message3(mailItem);
}else
{ MessageBox.Show("No MailItem selected!");}
}
}
private void Post_message3(MailItem outlookMessage ) {
MailMessage message = new MailMessage();
message.To.Add(new MailAddress(outlookMessage.SenderEmailAddress));
message.Subject = outlookMessage.Subject;
message.Body = outlookMessage.Body;
message.From = new MailAddress(REDMINE);
foreach (Microsoft.Office.Interop.Outlook.Attachment attachment in outlookMessage.Attachments)
{
string displayName = attachment.DisplayName;
int index = displayName.LastIndexOf('.');
string extension = index > -1 ? displayName.Substring(index) : string.Empty;
// Get the MIME content type of the attachment
string contentType = attachment.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x370E001F");
message.Attachments.Add(new System.Net.Mail.Attachment(attachment.PathName, contentType));
}
// Create a new SmtpClient object
SmtpClient client = new SmtpClient("172.26.106.79", 1025);
client.UseDefaultCredentials = false;
client.Send(message);
}
}
}
メール受信(python)
だいぶ、苦労したけど動きました。
ハマったこと
smtpのメッセージから、メール添付ファイルの取り出し(全部、CHATGPTに書かせた)
課題
メールの送信者のアドレスで、redmineに都度ログインする部分が出来ていない
→ まずはadminのTOKENでログインしている
python.py
import smtpd
import asyncore
import email
import os
from email.header import decode_header
from redminelib import Redmine
import pdb
from datetime import datetime, timedelta
SAVE_DIR = "./store"
def save_attachment(msg, save_dir):
filepaths = []
for part in msg.walk():
if part.get_content_maintype() == 'multipart':
continue
if part.get('Content-Disposition') is None:
continue
filename = part.get_filename()
if filename:
# Decode the filename if it's encoded
decoded_filename = decode_header(filename)[0][0]
if isinstance(decoded_filename, bytes):
# Handle bytes strings
decoded_filename = decoded_filename.decode()
# Remove any invalid characters from the filename
cleaned_filename = ''.join(c for c in decoded_filename if c.isalnum() or c in ['.', '_', '-'])
save_path = os.path.join(save_dir, cleaned_filename)
with open(save_path, 'wb') as f:
f.write(part.get_payload(decode=True))
print(f"Saved attachment: {cleaned_filename}")
filepaths.append(save_path)
print("All attachments saved successfully.")
return filepaths
# Define the function for parsing the email message
def mail_parse(msg):
email_data = {}
email_data['From'] = msg['from']
email_data['To'] = msg['to']
email_data['Subject'] = msg['subject']
email_data['Body']=msg['body']
# Extract body and add to email_data
for part in msg.walk():
if part.get_content_type() == 'text/plain':
body = part.get_payload(decode=True).decode()
email_data['Body'] = body
# Save attachments and add their filepaths to email_data
if msg.get_content_maintype() == 'multipart':
files = save_attachment(msg, SAVE_DIR)
email_data['Attachments'] = files
return email_data
class RedmineWork:
def __init__(self, url):
self.url = url
def api_login(self, api_key):
self.api = Redmine(self.url, key=api_key)
def get_all_pjt(self):
return self.api.project.all()
def push_ticket(self,msg,files):
projects = self.get_all_pjt()
for project in projects:
print(project.name)
issue = self.api.issue.new()
# 日付を設定
start_date = datetime.now().date()
issue.start_date = start_date
issue.due_date = start_date + timedelta(days=1) # Add one day to due date
issue.project_id = projects[0].id
issue.subject = msg["Subject"]
issue.description = ""
issue.tracker_id = 1#新規
issue.status_id = 1
issue.priority_id = 1
issue.assigned_to_id = 1
files_up = [{'path': file_path,'filename': os.path.basename(file_path)} for file_path in files]
issue.uploads = files_up
issue.save()
class CustomSMTPServer(smtpd.SMTPServer):
def __init__(self, localaddr, remoteaddr, redmine, **kwargs):
self.redmine = redmine
super().__init__(localaddr, remoteaddr, **kwargs)
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
msg = email.message_from_bytes(data)
files = save_attachment(msg, SAVE_DIR)
self.redmine.push_ticket(msg,files)
def start_server(url, api_key):
redmine = RedmineWork(url)
redmine.api_login(api_key)
# Create an instance of the custom SMTP server with redmine passed as argument
server = CustomSMTPServer(('localhost', 1025), None, redmine)
asyncore.loop()
if __name__ == "__main__":
url = r"http://redmine:8000"
api_key = "9e9c6a437feffbd06dc070e348f60e9eb1b7f027"
start_server(url, api_key)
参考
- Redmineに関連する記事
- 仕事で使うREMINEに関する考察(19)
- WIKI一発記入 仕事で使うREDMINEに関する考察(18)
- CHATGPTにてRedmine view customizerのHTML要素を生成する(4)
- チケット運用の盲点 仕事で使うREDMINEに関する考察(17)
- CHATGPTにてRedmine view customizerのHTML要素を生成する(3)
- CHATGPTにてRedmine view customizerのHTML要素を生成する(2)
- CHATGPTにてRedmine view customizerのHTML要素を生成する(1)
- CHATGPT便りの開発方針 仕事で使うREDMINEに関する考察(16)
- チケットからTODO作業へ落とし込み 仕事で使うREDMINEに関する考察(15)
- 仕事で使うREDMINEに関する考察(14)
- CHATGPT利活用 仕事で使うREDMINEに関する考察(12)
- やりたいことを少しずつ 仕事で使うREDMINEに関する考察(11)
- 組織を巻き込むプレゼン資料 仕事で使うREDMINEに関する考察(10)
- OfficeのフローにREDMINEをねじ込む 仕事で使うREDMINEに関する考察(9)
- RedmineチケットにCHATGPTを実装(超簡単)
- RedmineのチケットにCHATGPTを実装(2)
- Office365からRedmineへのメール送信してチケット登録
- Redmineプラグイン開発
- RedmineをTODOリストに使う 仕事で使うREDMINEに関する考察(8)
- 仕事で使うREDMINEに関する考察(7)
- 仕事で使うREDMINEに関する考察(6)
- 仕事で使うREDMINEに関する考察(5)
- 仕事で使うREDMINEに関する考察(4)
- 仕事で使うREDMINEに関する考察(3)
- 仕事で使うREDMINEに関する考察(2)
- 仕事で使うREDMINEに関する考察