LoginSignup
0
1

Office365からRedmineへのメール送信してチケット登録

Last updated at Posted at 2023-05-26

ハマったこと

この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)

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1